diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml index ba8d4bff968..6b64450d3d4 100644 --- a/.github/workflows/check-format.yml +++ b/.github/workflows/check-format.yml @@ -18,6 +18,7 @@ jobs: check-format: name: Check format runs-on: ubuntu-20.04 + if: github.repository_owner == 'Samsung' steps: - name: Checkout @@ -54,6 +55,7 @@ jobs: check-copyright: name: Check copyright runs-on: ubuntu-20.04 + if: github.repository_owner == 'Samsung' steps: - name: Checkout diff --git a/.github/workflows/check-pr-commit.yml b/.github/workflows/check-pr-commit.yml index 5dc2de1c390..9651514fd48 100644 --- a/.github/workflows/check-pr-commit.yml +++ b/.github/workflows/check-pr-commit.yml @@ -20,7 +20,7 @@ jobs: name: Check commit message runs-on: ubuntu-20.04 # Skip on draft, check on draft -> ready - if: github.event.pull_request.draft == false + if: github.repository_owner == 'Samsung' && github.event.pull_request.draft == false steps: - name: Checkout diff --git a/.github/workflows/run-onecc-build.yml b/.github/workflows/run-onecc-build.yml index ded12dde929..c12010d0aec 100644 --- a/.github/workflows/run-onecc-build.yml +++ b/.github/workflows/run-onecc-build.yml @@ -38,17 +38,23 @@ jobs: onecc-test: # Tested ubuntu version is decided by docker image, not runner runs-on: ubuntu-latest + if: github.repository_owner == 'Samsung' strategy: - # TODO Support various ubuntu version matrix: type: [ Debug, Release ] + ubuntu_code: [ focal, jammy ] + include: + - ubuntu_code: focal + ubuntu_ver: 20.04 + - ubuntu_code: jammy + ubuntu_ver: 22.04 container: - image: nnfw/one-devtools:focal + image: nnfw/one-devtools:${{ matrix.ubuntu_code }} options: --user root env: NNCC_WORKSPACE : build NNCC_INSTALL_PREFIX : install - name: onecc ubuntu 20.04 ${{ matrix.type }} test + name: onecc ubuntu ${{ matrix.ubuntu_ver }} ${{ matrix.type }} test steps: - name: Checkout @@ -67,7 +73,7 @@ jobs: uses: actions/cache@v4 with: path: ${{ env.NNCC_WORKSPACE }}/overlay - key: overlay-onecc-focal-${{ hashFiles('compiler/common-artifacts/CMakeLists.txt') }}-${{ hashFiles('infra/cmake/packages/**/*.cmake') }} + key: overlay-onecc-${{ matrix.ubuntu_code }}-${{ hashFiles('compiler/common-artifacts/CMakeLists.txt') }}-${{ hashFiles('infra/cmake/packages/**/*.cmake') }} - name: Build run: | diff --git a/.github/workflows/run-onert-android-build.yml b/.github/workflows/run-onert-android-build.yml index bfbbe857dac..ca016f2ee52 100644 --- a/.github/workflows/run-onert-android-build.yml +++ b/.github/workflows/run-onert-android-build.yml @@ -1,29 +1,38 @@ name: Run ONERT Android Release Build on: + push: + branches: + - master + - release/* + paths: + - '.github/workflows/run-onert-android-build.yml' + - 'nn*' + - 'Makefile.template' + - 'compute/**' + - 'infra/buildtool/**' + - 'infra/cmake/**' + - 'infra/nncc/**' + - 'infra/nnfw/**' + - 'runtime/**' + - 'tests/**' + - '!**/*.md' pull_request: branches: - master - release/* paths: - '.github/workflows/run-onert-android-build.yml' - - 'nnas' - - 'nnfw' + - 'nn*' - 'Makefile.template' - 'compute/**' - - 'infra/**' - - '!infra/debian/**' - - '!infra/docker/**' - - '!infra/doxygen/**' - - '!infra/git-hooks/**' - - '!infra/nncc/**' - - '!infra/onert-micro/**' - - '!infra/packaging/**' - - 'nnpackage/**' - - '!nnpackage/spec/**' + - 'infra/buildtool/**' + - 'infra/cmake/**' + - 'infra/nncc/**' + - 'infra/nnfw/**' - 'runtime/**' - 'tests/**' - - '!**.md' + - '!**/*.md' defaults: run: @@ -32,6 +41,7 @@ defaults: jobs: build: runs-on: ubuntu-22.04 + if: github.repository_owner == 'Samsung' env: TARGET_ARCH: aarch64 TARGET_OS: android @@ -45,8 +55,9 @@ jobs: uses: actions/cache@v4 with: path: externals - key: external-onert-ndk26 + key: external-onert-ndk26-${{ hashFiles('infra/cmake/packages/**/*.cmake') }}-${{ hashFiles('infra/nnfw/cmake/packages/**/*.cmake') }} restore-keys: | + external-onert-ndk26- external-onert-ndk external-onert- external- diff --git a/.github/workflows/run-onert-micro-unit-tests.yml b/.github/workflows/run-onert-micro-unit-tests.yml index 3256c758c4d..28df490b059 100644 --- a/.github/workflows/run-onert-micro-unit-tests.yml +++ b/.github/workflows/run-onert-micro-unit-tests.yml @@ -1,6 +1,13 @@ name: Run onert-micro Unit tests on: + push: + branches: + - master + - release/* + paths: + - 'onert-micro/**' + - '.github/workflows/run-onert-micro-unit-tests.yml' pull_request: branches: - master @@ -23,7 +30,7 @@ jobs: name: Run onert-micro Unit tests runs-on: ubuntu-20.04 # Skip on draft, check on draft -> ready - if: github.event.pull_request.draft == false + if: github.repository_owner == 'Samsung' && github.event.pull_request.draft == false steps: - name: Install Arm GNU Toolchain (arm-none-eabi-gcc) diff --git a/compiler/circledump/driver/Driver.cpp b/compiler/circledump/driver/Driver.cpp index 5b0871a91ae..f5fd9f8268a 100644 --- a/compiler/circledump/driver/Driver.cpp +++ b/compiler/circledump/driver/Driver.cpp @@ -50,7 +50,11 @@ int entry(int argc, char **argv) std::cout << "Dump: " << circle_path << std::endl << std::endl; - std::cout << circlemodel << std::endl; + circledump::ModelEx modelex; + modelex.model = circlemodel; + modelex.rawdata = &modelData; + + std::cout << modelex << std::endl; return 0; } diff --git a/compiler/circledump/include/circledump/Dump.h b/compiler/circledump/include/circledump/Dump.h index a129458f416..2d25a6178c6 100644 --- a/compiler/circledump/include/circledump/Dump.h +++ b/compiler/circledump/include/circledump/Dump.h @@ -24,9 +24,16 @@ namespace circledump { -void dump_model(std::ostream &os, const circle::Model *model); -} +struct ModelEx +{ + const circle::Model *model; + const std::vector *rawdata; +}; + +void dump_model(std::ostream &os, const circledump::ModelEx &model); + +} // namespace circledump -std::ostream &operator<<(std::ostream &os, const circle::Model *model); +std::ostream &operator<<(std::ostream &os, const circledump::ModelEx &model); #endif // __CIRCLEDUMP_DUMP_H__ diff --git a/compiler/circledump/src/Dump.cpp b/compiler/circledump/src/Dump.cpp index 166931648f8..999799f9bfa 100644 --- a/compiler/circledump/src/Dump.cpp +++ b/compiler/circledump/src/Dump.cpp @@ -341,9 +341,9 @@ void dump_sub_graph(std::ostream &os, mio::circle::Reader &reader) os << std::endl; } -void dump_model(std::ostream &os, const circle::Model *model) +void dump_model(std::ostream &os, const circle::Model *model, const std::vector *rawdata) { - mio::circle::Reader reader(model); + mio::circle::Reader reader(model, rawdata); uint32_t num_subgraph = reader.num_subgraph(); @@ -378,13 +378,17 @@ void dump_model(std::ostream &os, const circle::Model *model) os << std::endl; // dump buffer - os << "Buffers: B(index) (length) values, if any" << std::endl; + os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl; for (uint32_t i = 0; i < buffers->size(); ++i) { + bool ext_offset = false; const uint8_t *buff_data; - size_t size = reader.buffer_info(i, &buff_data); + size_t size = reader.buffer_info(i, &buff_data, ext_offset); - os << "B(" << i << ") (" << size << ") "; + os << "B(" << i << ") (" << size; + if (ext_offset) + os << " *"; + os << ") "; if (buff_data != nullptr) { dump_buffer(os, buff_data, size, 16); @@ -460,8 +464,8 @@ void dump_model(std::ostream &os, const circle::Model *model) } // namespace circledump -std::ostream &operator<<(std::ostream &os, const circle::Model *model) +std::ostream &operator<<(std::ostream &os, const circledump::ModelEx &modelex) { - circledump::dump_model(os, model); + circledump::dump_model(os, modelex.model, modelex.rawdata); return os; } diff --git a/compiler/luci-interpreter/pal/linux/PALConv2d.h b/compiler/luci-interpreter/pal/linux/PALConv2d.h index 8ffcd864b21..0ce83fc6e35 100644 --- a/compiler/luci-interpreter/pal/linux/PALConv2d.h +++ b/compiler/luci-interpreter/pal/linux/PALConv2d.h @@ -30,14 +30,30 @@ static inline void Conv(const tflite::ConvParams ¶ms, const tflite::RuntimeS float *scratchpad_data) { (void)scratchpad_shape; - if (scratchpad_data) + + const int32_t batches = tflite::MatchingDim(input_shape, 0, output_shape, 0); + const int32_t input_depth = tflite::MatchingDim(input_shape, 3, filter_shape, 3); + const int32_t output_height = output_shape.Dims(1); + const int32_t output_width = output_shape.Dims(2); + const int32_t filter_height = filter_shape.Dims(1); + const int32_t filter_width = filter_shape.Dims(2); + + int64_t im2col_flat_size = 1; + im2col_flat_size *= batches; + im2col_flat_size *= output_height; + im2col_flat_size *= output_width; + im2col_flat_size *= input_depth; + im2col_flat_size *= filter_height; + im2col_flat_size *= filter_width; + + // This condition checks if integer overflow will occur inside the optimized kernel. + // https://github.com/tensorflow/tensorflow/blob/v2.12.1/tensorflow/lite/kernels/internal/optimized/im2col_utils.h#L81 + // If overflow is expected, we fall back to the reference kernel. + // NOTE This is just a rough check. + bool opt_kernel_overflow = im2col_flat_size > std::numeric_limits::max(); + + if (scratchpad_data and not opt_kernel_overflow) { - const int32_t batches = tflite::MatchingDim(input_shape, 0, output_shape, 0); - const int32_t input_depth = tflite::MatchingDim(input_shape, 3, filter_shape, 3); - const int32_t output_height = output_shape.Dims(1); - const int32_t output_width = output_shape.Dims(2); - const int32_t filter_height = filter_shape.Dims(1); - const int32_t filter_width = filter_shape.Dims(2); tflite::RuntimeShape im2col_shape{batches, output_height, output_width, input_depth * filter_height * filter_width}; diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp index c0d23882da3..aa3c4df6ed8 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp @@ -19,7 +19,7 @@ #include "kernels/Utils.h" -#include +#include namespace luci_interpreter { @@ -40,12 +40,12 @@ void MirrorPad::configure() if (num_dims > 4) throw std::runtime_error("Unsupported number of dimensions."); - assert(output()->element_type() == input()->element_type()); - assert(paddings()->element_type() == DataType::S32); + LUCI_INTERPRETER_CHECK(output()->element_type() == input()->element_type()); + LUCI_INTERPRETER_CHECK(paddings()->element_type() == DataType::S32); // Paddings shape should be [N, 2]. - assert(paddings()->shape().num_dims() == 2); - assert(paddings()->shape().dim(0) == num_dims); - assert(paddings()->shape().dim(1) == 2); + LUCI_INTERPRETER_CHECK(paddings()->shape().num_dims() == 2); + LUCI_INTERPRETER_CHECK(paddings()->shape().dim(0) == num_dims); + LUCI_INTERPRETER_CHECK(paddings()->shape().dim(1) == 2); Shape output_shape(num_dims); const auto *paddings_data = getTensorData(paddings()); @@ -53,118 +53,140 @@ void MirrorPad::configure() { const int32_t padding_before = paddings_data[i * 2]; const int32_t padding_after = paddings_data[i * 2 + 1]; - assert(padding_before >= 0 && padding_after >= 0); + LUCI_INTERPRETER_CHECK(padding_before >= 0 && padding_after >= 0); output_shape.dim(i) = input_shape.dim(i) + padding_before + padding_after; } output()->resize(output_shape); } +namespace +{ + +// Helper method that fills the left and right pads. template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output); +inline void getPadding(const T *data, int offset, int64_t *left_pad, int64_t *right_pad) +{ + *left_pad = static_cast(*(data + offset * 2)); + *right_pad = static_cast(*(data + offset * 2 + 1)); +} -void MirrorPad::execute() const +// Given dimension index and the left/right padding. +// Returns the corresponding dimension in the input array. +inline int getInputDimension(int padded_dimension, int left_pad, int right_pad, int input_dim_size, + int offset) { - switch (input()->element_type()) + (void)right_pad; + + if (padded_dimension < left_pad) { - case DataType::FLOAT32: + const int original_ind = left_pad + offset - 1; + return original_ind - (std::min(padded_dimension, original_ind - offset)); + } + padded_dimension -= left_pad; + if (padded_dimension >= input_dim_size) + { + padded_dimension -= input_dim_size; + const int original_ind = input_dim_size - (1 + offset); + return original_ind - std::min(padded_dimension, original_ind); + } + return padded_dimension; +} + +// Given and index in output array, returns the index of the value +// in input array. +int getFlatIndex(int index, int num_dims, const DataType padding_matrix_type, + const uint8_t *padding_matrix_data, const int32_t *input_dims, + int *output_dims_num_elements, int *input_dims_num_elements, const int offset) +{ + int flat_index = 0; + int64_t left_pad = 0, right_pad = 0, dimension_index, index_in_input; + + for (int i = 0; i < num_dims; ++i) + { + switch (padding_matrix_type) { - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); - break; + case DataType::S32: + getPadding(reinterpret_cast(padding_matrix_data), i, &left_pad, + &right_pad); + break; + case DataType::S64: + getPadding(reinterpret_cast(padding_matrix_data), i, &left_pad, + &right_pad); + break; + default: + break; } - case DataType::U8: - { - assert(output()->zero_point() >= std::numeric_limits::min()); - assert(output()->zero_point() <= std::numeric_limits::max()); + dimension_index = index / output_dims_num_elements[i]; - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); - break; - } - default: - throw std::runtime_error("luci-intp MirrorPad Unsupported type."); + index_in_input = getInputDimension(dimension_index, left_pad, right_pad, input_dims[i], offset); + + flat_index += index_in_input * input_dims_num_elements[i]; + index %= output_dims_num_elements[i]; } + + return flat_index; } template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output) +void eval(const DataType padding_matrix_type, const uint8_t *padding_matrix_data, + const int32_t *input_dims, int *output_dims_num_elements, int *input_dims_num_elements, + const T *input_data, T *output_data, const int offset, const int num_dims, + const int output_size) { - auto const input_dims = input.shape().num_dims(); - auto const input_data = input.data(); - auto const paddings_data = paddings.data(); - auto const output_data = output.data(); - - auto const input_b = input_dims > 3 ? input.shape().dim(input_dims - 4) : 1; - auto const input_h = input_dims > 2 ? input.shape().dim(input_dims - 3) : 1; - auto const input_w = input_dims > 1 ? input.shape().dim(input_dims - 2) : 1; - auto const input_d = input.shape().dim(input_dims - 1); - - auto const input_h_offset = input_d * input_w; - auto const input_b_offset = input_h_offset * input_h; - - auto const output_b = input_dims > 3 ? output.shape().dim(input_dims - 4) : 1; - auto const output_h = input_dims > 2 ? output.shape().dim(input_dims - 3) : 1; - auto const output_w = input_dims > 1 ? output.shape().dim(input_dims - 2) : 1; - auto const output_d = output.shape().dim(input_dims - 1); - - auto const left_b_pad = paddings_data[2 * (input_dims - 4)]; - auto const left_h_pad = paddings_data[2 * (input_dims - 3)]; - auto const left_w_pad = paddings_data[2 * (input_dims - 2)]; - auto const left_d_pad = paddings_data[2 * (input_dims - 1)]; - - auto const right_b_pad = paddings_data[2 * (input_dims - 4) + 1]; - auto const right_h_pad = paddings_data[2 * (input_dims - 3) + 1]; - auto const right_w_pad = paddings_data[2 * (input_dims - 2) + 1]; - auto const right_d_pad = paddings_data[2 * (input_dims - 1) + 1]; - - const auto positive_mod = [](auto a, auto b) { return (a % b + b) % b; }; - const auto offset_index = [input_d, input_h_offset, input_b_offset](auto d, auto w, auto h, - auto b) { - return d + w * input_d + h * input_h_offset + b * input_b_offset; - }; - - const auto symmetric_dim = [&positive_mod](auto i, auto left_pad, auto input) { - bool reflected = (((i < left_pad ? i + 1 - input : i) - left_pad) / input & 1) == 1; - return positive_mod(reflected ? input + left_pad - i - 1 : i - left_pad, input); - }; - - const T *in_ptr = input_data; - T *out_ptr = output_data; - - for (int32_t b = 0; b < output_b; ++b) + for (int i = 0; i < output_size; ++i) { - for (int32_t h = 0; h < output_h; ++h) - { - for (int32_t w = 0; w < output_w; ++w) - { - for (int32_t d = 0; d < output_d; ++d) - { - if (b < left_b_pad || b >= output_b - right_b_pad || // - h < left_h_pad || h >= output_h - right_h_pad || // - w < left_w_pad || w >= output_w - right_w_pad || // - d < left_d_pad || d >= output_d - right_d_pad) - { - if (mode == MirrorPadMode::REFLECT) - { - *out_ptr++ = input_data[offset_index( - positive_mod(d - left_d_pad, input_d), positive_mod(w - left_w_pad, input_w), - positive_mod(h - left_h_pad, input_h), positive_mod(b - left_b_pad, input_b))]; - } - else - { - *out_ptr++ = input_data[offset_index( - symmetric_dim(d, left_d_pad, input_d), symmetric_dim(w, left_w_pad, input_w), - symmetric_dim(h, left_h_pad, input_h), symmetric_dim(b, left_b_pad, input_b))]; - } - } - else - { - *out_ptr++ = *in_ptr++; - } - } - } - } + int index = getFlatIndex(i, num_dims, padding_matrix_type, padding_matrix_data, input_dims, + output_dims_num_elements, input_dims_num_elements, offset); + output_data[i] = input_data[index]; + } +} + +} // namespace + +void MirrorPad::execute() const +{ + const Tensor &t_input = *input(); + const Tensor &t_paddings = *paddings(); + Tensor &t_output = *output(); + + const auto offset = params().mode != MirrorPadMode::REFLECT ? 0 : 1; + const auto input_dims = t_input.shape().num_dims(); + const auto output_size = t_output.shape().num_elements(); + + int output_dims_num_elements[5]; + int input_dims_num_elements[5]; + int32_t input_shape_dim[5]; + + for (int i = 0; i < input_dims; i++) + { + output_dims_num_elements[i] = 1; + input_dims_num_elements[i] = 1; + input_shape_dim[i] = t_input.shape().dim(i); + } + + for (int i = input_dims - 2; i >= 0; i--) + { + output_dims_num_elements[i] = output_dims_num_elements[i + 1] * t_output.shape().dim(i + 1); + input_dims_num_elements[i] = input_dims_num_elements[i + 1] * t_input.shape().dim(i + 1); + } + + switch (t_input.element_type()) + { + case DataType::FLOAT32: + eval(t_paddings.element_type(), t_paddings.data(), input_shape_dim, + output_dims_num_elements, input_dims_num_elements, t_input.data(), + t_output.data(), offset, input_dims, output_size); + break; + + case DataType::U8: + eval(t_paddings.element_type(), t_paddings.data(), input_shape_dim, + output_dims_num_elements, input_dims_num_elements, t_input.data(), + t_output.data(), offset, input_dims, output_size); + break; + + default: + throw std::runtime_error("luci-intp MirrorPad Unsupported type."); } } diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp index 740d8cb2272..cef7d83da5c 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp @@ -48,12 +48,12 @@ class MirrorPadTest : public ::testing::Test TEST_F(MirrorPadTest, FloatReflect) { - Shape input_shape = {1, 2, 2, 1}; + Shape input_shape = {1, 2, 3, 1}; Shape padding_shape = {4, 2}; - std::vector input_data{1.0f, 2.0f, // - 3.0f, 4.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 2, 0, 0}; + std::vector input_data{1.0f, 2.0f, 3.0f, // + 4.0f, 5.0f, 6.0f}; // + std::vector padding_data{0, 0, 1, 1, 1, 1, 0, 0}; Tensor input_tensor = makeInputTensor(input_shape, input_data, _memory_manager.get()); @@ -64,12 +64,35 @@ TEST_F(MirrorPadTest, FloatReflect) Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - std::vector ref_output_data{2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; // - std::initializer_list ref_output_shape{1, 5, 5, 1}; + std::vector ref_output_data{5, 4, 5, 6, 5, 2, 1, 2, 3, 2, // + 5, 4, 5, 6, 5, 2, 1, 2, 3, 2}; // + std::initializer_list ref_output_shape{1, 4, 5, 1}; + + EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); +} + +TEST_F(MirrorPadTest, FloatReflect2) +{ + Shape input_shape = {2, 3}; + Shape padding_shape = {2, 2}; + + std::vector input_data{1, 2, 3, 4, 5, 6}; + std::vector padding_data{1, 1, 2, 2}; + + Tensor input_tensor = + makeInputTensor(input_shape, input_data, _memory_manager.get()); + Tensor padding_tensor = + makeInputTensor(padding_shape, padding_data, _memory_manager.get()); + + Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); + + Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); + + std::vector ref_output_data{6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1, + 6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1}; + + std::initializer_list ref_output_shape{4, 7}; EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); @@ -138,7 +161,7 @@ TEST_F(MirrorPadTest, Uint8Reflect) std::vector input_data{1.0f, 2.0f, 3.0f, // 4.0f, 5.0f, 6.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 3, 0, 0}; + std::vector padding_data{0, 0, 1, 1, 1, 1, 0, 0}; Tensor input_tensor = makeInputTensor( input_shape, quant_param.first, quant_param.second, input_data, _memory_manager.get()); @@ -150,14 +173,9 @@ TEST_F(MirrorPadTest, Uint8Reflect) Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - std::vector ref_output_data{ - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - }; - std::initializer_list ref_output_shape{1, 5, 7, 1}; + std::vector ref_output_data{5, 4, 5, 6, 5, 2, 1, 2, 3, 2, // + 5, 4, 5, 6, 5, 2, 1, 2, 3, 2}; // + std::initializer_list ref_output_shape{1, 4, 5, 1}; EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data, quant_tolerance)); diff --git a/compiler/luci-value-py-test/test.lst b/compiler/luci-value-py-test/test.lst index 2c928fb8d95..f7f3b86b163 100644 --- a/compiler/luci-value-py-test/test.lst +++ b/compiler/luci-value-py-test/test.lst @@ -93,7 +93,7 @@ eval(Mean_000) eval(Mean_001) eval(Mean_U8_000) eval(Minimum_000) -#eval(MirrorPad_000) +eval(MirrorPad_000) eval(Mul_000) #eval(Mul_U8_000) eval(Neg_000) diff --git a/compiler/luci/export/include/luci/CircleExporter.h b/compiler/luci/export/include/luci/CircleExporter.h index 0584c623cfa..de064ea8444 100644 --- a/compiler/luci/export/include/luci/CircleExporter.h +++ b/compiler/luci/export/include/luci/CircleExporter.h @@ -36,14 +36,9 @@ class CircleExporter virtual ~Contract() = default; public: // Client -> Exporter - // Input Graph (to be exported) - // Exporter expects a loco graph that consists of Circle nodes - virtual loco::Graph *graph(void) const = 0; - // Input Module (to be exported) // Exporter expects a luci module that consists of loco graphs - // TODO make this pure virtual - virtual luci::Module *module(void) const; + virtual luci::Module *module(void) const = 0; public: // Exporter -> Client // Exporter calls store for export data diff --git a/compiler/luci/export/include/luci/CircleFileExpContract.h b/compiler/luci/export/include/luci/CircleFileExpContract.h index 8ef1b5e0cf6..a06ebe9963e 100644 --- a/compiler/luci/export/include/luci/CircleFileExpContract.h +++ b/compiler/luci/export/include/luci/CircleFileExpContract.h @@ -40,7 +40,6 @@ struct CircleFileExpContract : public luci::CircleExporter::Contract virtual ~CircleFileExpContract() = default; public: - loco::Graph *graph(void) const final { return nullptr; } luci::Module *module(void) const final { return _module; } public: diff --git a/compiler/luci/export/src/CircleExporter.cpp b/compiler/luci/export/src/CircleExporter.cpp index 125df780212..6f5066823c2 100644 --- a/compiler/luci/export/src/CircleExporter.cpp +++ b/compiler/luci/export/src/CircleExporter.cpp @@ -26,9 +26,6 @@ namespace luci { -// TODO remove this -Module *CircleExporter::Contract::module(void) const { return nullptr; } - CircleExporter::CircleExporter() { // NOTHING TO DO @@ -48,17 +45,10 @@ bool CircleExporter::invoke(Contract *contract) const return contract->store(ptr, size); } - auto graph = contract->graph(); - if (graph == nullptr) - return false; - - CircleExporterImpl impl(graph); - - const char *ptr = impl.getBufferPointer(); - const size_t size = impl.getBufferSize(); + // NOTE some unit tests calls with nullptr module, cannot add assert here + // TODO fix those unit tests and add assert(false) - // we just send one time - return contract->store(ptr, size); + return false; } } // namespace luci diff --git a/compiler/luci/export/src/CircleExporter.test.cpp b/compiler/luci/export/src/CircleExporter.test.cpp index 5898f9d653e..c76d983972d 100644 --- a/compiler/luci/export/src/CircleExporter.test.cpp +++ b/compiler/luci/export/src/CircleExporter.test.cpp @@ -33,12 +33,12 @@ class SampleGraphContract : public luci::CircleExporter::Contract SampleGraphContract() : luci::CircleExporter::Contract(), _buffer(new std::vector) { // create needed entities - _g = loco::make_graph(); - auto graph_input = _g->inputs()->create(); - auto graph_output = _g->outputs()->create(); - input_node = _g->nodes()->create(); - output_node = _g->nodes()->create(); - relu_node = _g->nodes()->create(); + auto g = loco::make_graph(); + auto graph_input = g->inputs()->create(); + auto graph_output = g->outputs()->create(); + input_node = g->nodes()->create(); + output_node = g->nodes()->create(); + relu_node = g->nodes()->create(); // link nodes and link them to graph relu_node->features(input_node); @@ -57,9 +57,12 @@ class SampleGraphContract : public luci::CircleExporter::Contract graph_output->shape({1, 2, 3, 4}); graph_output->dtype(loco::DataType::FLOAT32); + + _m = std::unique_ptr{new luci::Module}; + _m->add(std::move(g)); } - loco::Graph *graph(void) const override { return _g.get(); } + luci::Module *module(void) const override { return _m.get(); } public: bool store(const char *ptr, const size_t size) const override @@ -77,7 +80,7 @@ class SampleGraphContract : public luci::CircleExporter::Contract luci::CircleRelu *relu_node; private: - std::unique_ptr _g; + std::unique_ptr _m; std::unique_ptr> _buffer; }; diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp index 014ef45d71c..00e7ace2c99 100644 --- a/compiler/luci/export/src/CircleExporterImpl.cpp +++ b/compiler/luci/export/src/CircleExporterImpl.cpp @@ -15,14 +15,18 @@ */ #include "CircleExporterImpl.h" -#include "Optimize.h" #include "CircleExportMetadata.h" #include "CircleTensorExporter.h" #include "CircleOperationExporter.h" #include "CircleExporterUtils.h" +#include "ProgressReporter.h" #include +#include +#include +#include +#include #include #include #include @@ -100,13 +104,35 @@ encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map()); + phase.emplace_back(std::make_unique()); + + // TODO add more optimization passes (with a knob) + } + + logo::PhaseRunner phase_runner{g}; + + luci::ProgressReporter prog(g, logo::PhaseStrategy::Restart); + phase_runner.attach(&prog); + phase_runner.run(phase); +} + +} // namespace + namespace luci { using namespace circle; using namespace flatbuffers; -CircleExporterImpl::CircleExporterImpl(loco::Graph *graph) { exportGraph(graph); } CircleExporterImpl::CircleExporterImpl(Module *module) { exportModule(module); } ::flatbuffers::Offset<::circle::SubGraph> @@ -121,61 +147,6 @@ CircleExporterImpl::exportSubgraph(SerializedGraphData &gd) return subgraph; } -void CircleExporterImpl::exportGraph(loco::Graph *graph) -{ - // do graph optimization - optimize(graph); - - _builder.Clear(); - - SerializedModelData md; - SerializedGraphData gd; - - // This version is taken from comment in fbs - constexpr uint32_t version = 0; - - // set Subgraph name - gd._name = graph->name(); - - // TODO set this value properly - gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST; - - // prepare model data - prepareModelData(_builder, md); - - // parse graph into SerializedModelData structure - exportOpDefinedTensors(graph, _builder, md, gd); - - // NOTE Invoke these register functions only after each node is annotated with its tensor_index - registerGraphInputTensors(graph, gd); - registerGraphOutputTensors(graph, gd); - - exportNodes(graph, _builder, md, gd); - - // encode operator codes - auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); - - // Subgraphs - Offset subgraph = exportSubgraph(gd); - auto subgraphs = _builder.CreateVector(std::vector>{subgraph}); - - // Description - std::string description_str = "nnpackage"; - auto description = _builder.CreateString(description_str); - - // Metadata - auto metadata_vec = createCircleMetadataVector(_builder, md); - auto metadata = _builder.CreateVector(std::vector>(metadata_vec)); - - // create array of buffers - auto buffers = _builder.CreateVector(md._buffers); - - // Model - auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description, - buffers, 0 /* metadata_buffer */, metadata); - FinishModelBuffer(_builder, model_offset); -} - void CircleExporterImpl::exportModule(Module *module) { assert(module->size() > 0); @@ -221,7 +192,7 @@ void CircleExporterImpl::exportModule(Module *module) auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); // Description - std::string description_str = "nnpackage"; + std::string description_str = "ONE-luci/export"; auto description = _builder.CreateString(description_str); // Metadata diff --git a/compiler/luci/export/src/CircleExporterImpl.h b/compiler/luci/export/src/CircleExporterImpl.h index 069f62afd4a..5911fadba43 100644 --- a/compiler/luci/export/src/CircleExporterImpl.h +++ b/compiler/luci/export/src/CircleExporterImpl.h @@ -38,7 +38,6 @@ class CircleExporterImpl CircleExporterImpl() = delete; ~CircleExporterImpl() = default; - explicit CircleExporterImpl(loco::Graph *graph); explicit CircleExporterImpl(Module *module); /** @@ -59,12 +58,6 @@ class CircleExporterImpl */ flatbuffers::Offset exportSubgraph(SerializedGraphData &gd); - /** - * @brief root function that writes graph into internal buffer - * @param graph - */ - void exportGraph(loco::Graph *graph); - /** * @brief root function that writes Module into internal buffer * @param module diff --git a/compiler/luci/export/src/Optimize.cpp b/compiler/luci/export/src/Optimize.cpp deleted file mode 100644 index e59f15204a3..00000000000 --- a/compiler/luci/export/src/Optimize.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Optimize.h" -#include "ProgressReporter.h" - -#include -#include - -#include - -#include - -namespace luci -{ - -void optimize(loco::Graph *g) -{ - logo::Phase phase; - { - // prepare type and shape before optimization - phase.emplace_back(std::make_unique()); - phase.emplace_back(std::make_unique()); - - // TODO add more optimization passes (with a knob) - } - - logo::PhaseRunner phase_runner{g}; - - ProgressReporter prog(g, logo::PhaseStrategy::Restart); - phase_runner.attach(&prog); - phase_runner.run(phase); -} - -} // namespace luci diff --git a/compiler/luci/export/src/SerializedData.h b/compiler/luci/export/src/SerializedData.h index 136a8ac490e..044593691ba 100644 --- a/compiler/luci/export/src/SerializedData.h +++ b/compiler/luci/export/src/SerializedData.h @@ -139,7 +139,7 @@ struct SerializedModelData final struct SerializedGraphData final : public SubGraphContext { SerializedGraphData() = default; - SerializedGraphData(const SerializedModelData &) = delete; + SerializedGraphData(const SerializedGraphData &) = delete; std::vector> _operators; std::vector> _tensors; diff --git a/compiler/luci/pass/include/luci/CircleOptimizer.h b/compiler/luci/pass/include/luci/CircleOptimizer.h index 9cbd26f0da5..8a1eb6d4f78 100644 --- a/compiler/luci/pass/include/luci/CircleOptimizer.h +++ b/compiler/luci/pass/include/luci/CircleOptimizer.h @@ -49,6 +49,7 @@ class CircleOptimizer final FuseMeanWithMean, FuseMulWithConv, FuseMulWithDiv, + FuseMulWithFullyConnected, FuseTransposeWithMean, ResolveCustomOpAdd, ResolveCustomOpBatchMatMul, diff --git a/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h b/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h new file mode 100644 index 00000000000..718039f1c69 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ +#define __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ + +#include + +namespace luci +{ + +/** + * @brief Class to fuse Mul into CircleFullyConnected + */ +struct FuseMulWithFullyConnectedPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::FuseMulWithFullyConnectedPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp index 840c8dd25dd..246d4f36e78 100644 --- a/compiler/luci/pass/src/CircleOptimizer.cpp +++ b/compiler/luci/pass/src/CircleOptimizer.cpp @@ -48,6 +48,7 @@ #include "luci/Pass/FuseMeanWithMeanPass.h" #include "luci/Pass/FuseMulWithConvPass.h" #include "luci/Pass/FuseMulWithDivPass.h" +#include "luci/Pass/FuseMulWithFullyConnectedPass.h" #include "luci/Pass/FusePreActivationBatchNormPass.h" #include "luci/Pass/FusePReluPass.h" #include "luci/Pass/FuseGeluPass.h" @@ -310,6 +311,10 @@ void CircleOptimizer::optimize(loco::Graph *g) const { phase.emplace_back(std::make_unique()); } + if (_options->query(Options::Algorithm::FuseMulWithFullyConnected)) + { + phase.emplace_back(std::make_unique()); + } if (_options->query(Options::Algorithm::ResolveCustomOpMaxPoolWithArgmax)) { phase.emplace_back(std::make_unique()); diff --git a/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp new file mode 100644 index 00000000000..3049862e216 --- /dev/null +++ b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/FuseMulWithFullyConnectedPass.h" + +#include "helpers/NodeFiller.h" + +#include +#include +#include + +namespace +{ + +#define RETURN_FALSE_UNLESS(cond) \ + if (not(cond)) \ + return false; + +inline bool is_single_element(const luci::CircleConst *node) +{ + return ((node->rank() == 1 || node->rank() == 0) && node->size() == 1); +} + +inline void update_with_single_element(luci::CircleConst *fused_node, + const luci::CircleConst *multiplication) +{ + for (uint32_t i = 0; i < fused_node->size(); i++) + { + fused_node->at(i) *= multiplication->at(0); + } +} + +luci::CircleConst *gen_fused_weights(luci::CircleConst *weights, + const luci::CircleConst *multiplication) +{ + auto fused_weights = luci::clone(weights); + // Single element multiplication: + if (is_single_element(multiplication)) + { + update_with_single_element(fused_weights, multiplication); + } + // N-size multiplication: + else + { + // Go along channels, multiplication size is ensured to be compatible with channels. + auto count = fused_weights->dim(0).value(); + auto size = fused_weights->dim(fused_weights->rank() - 1).value(); + float val; + for (uint32_t c = 0; c < count; c++) + { + val = multiplication->at(c); + for (uint32_t i = 0; i < size; i++) + { + fused_weights->at(c * size + i) *= val; + } + } + } + return fused_weights; +} + +luci::CircleConst *gen_fused_bias(luci::CircleConst *bias, const luci::CircleConst *multiplication) +{ + auto fused_bias = luci::clone(bias); + // Single element multiplication: + if (is_single_element(multiplication)) + { + update_with_single_element(fused_bias, multiplication); + } + // N-size multiplication: + else + { + // Go along channels, multiplication size is ensured to be compatible with channels. + for (uint32_t i = 0; i < fused_bias->size(); i++) + { + fused_bias->at(i) *= multiplication->at(i); + } + } + return fused_bias; +} + +/** + * Fuse Mul to FullyConnected if the multiplied value is a channel(last dimension)-wise constant + * + * BEFORE + * | + * [CircleFullyConnected] + * | + * [CircleMul] + * | + * + * AFTER + * | + * [CircleFullyConnected] [CircleMul] (dead) + * | + * + */ +bool fuse_mul_with_fc(luci::CircleMul *mul) +{ + // Sanity check: + RETURN_FALSE_UNLESS(mul); + // Allow Mul node only with FLOAT32 data type: + RETURN_FALSE_UNLESS(mul->dtype() == loco::DataType::FLOAT32); + // Check if any FC node connects to Mul. + // Find the pattern of Mul(FC, CircleConst): + luci::CircleFullyConnected *fc = nullptr; + luci::CircleConst *multiplication = nullptr; + RETURN_FALSE_UNLESS(luci::fill(&fc, &multiplication).with_commutative_args_of(mul)); + /** + * Make sure that FullyConnected has only one successor. + * + * If the FullyConnected output is connected to more nodes, + * this pass will replace node with new fused FullyConnected. + * Thus pass success will only introduce extra FullyConnected + * without reducing overall number of nodes. + * Which tends to increase model's size and degrades model's performance. + * Thus one successor is required to benefit from this pass. + * + * Example graph that illustrates the described scenario: + * + * BEFORE + * | + * [CircleFullyConnected] + * | + * +-------+----------------+ + * | | + * | | + * [Other Node] [CircleMul] + * | | + * + * AFTER + * | + * +-----------------------+ + * | | + * | | + * [CircleFullyConnected] | + * | | + * +-------+ | + * | | + * | | + * [Other Node] [New CircleFullyConnected Fused with Mul] + * | | + * + */ + RETURN_FALSE_UNLESS(loco::succs(fc).size() == 1); + // Allow only FLOAT32 data type: + RETURN_FALSE_UNLESS(fc->dtype() == loco::DataType::FLOAT32); + // Allow only without activation functions as values are going to + // be multiplied before activation function. + RETURN_FALSE_UNLESS(fc->fusedActivationFunction() == luci::FusedActFunc::NONE); + // Check for weights being Constant: + auto weights = dynamic_cast(fc->weights()); + RETURN_FALSE_UNLESS(weights); + // Get rank of multiplication: + auto rank = multiplication->rank(); + // Check that all dimensions are ones, checks broadcast capabilites. + // Last dimesion of multiplication must be compatible with FC. + // N-D case (N>1): + if (multiplication->rank() > 1) + { + // Check channel-wise broadcasting: + for (uint32_t i = 0; i < rank - 1; i++) + RETURN_FALSE_UNLESS(multiplication->dim(i).value() == 1); + // Check the last dimesion of Mul is the same with the first dimension of FullyConnected + RETURN_FALSE_UNLESS(multiplication->dim(rank - 1) == weights->dim(0)); + } + // 1-D or scalar case: + else if (multiplication->rank() == 1) + { + RETURN_FALSE_UNLESS(multiplication->size() == 1 || + multiplication->size() == weights->dim(0)); + } + else if (multiplication->rank() == 0) + { + RETURN_FALSE_UNLESS(multiplication->size() == 1); + } + + // Only supports: + // (1) constant bias + // (2) no bias + auto bias = loco::must_cast(fc->bias()); + if (bias->opcode() == luci::CircleOpcode::CIRCLECONST) + { + // Create new bias to be updated with values: + auto const_bias = dynamic_cast(fc->bias()); + RETURN_FALSE_UNLESS(const_bias) + RETURN_FALSE_UNLESS(const_bias->dtype() == loco::DataType::FLOAT32); + // Create new bias with updated values and replace: + auto fused_bias = gen_fused_bias(const_bias, multiplication); + fc->bias(fused_bias); + } + else if (bias->opcode() != luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE) + { + return false; + } + + // Create new weights with updated values and replace: + auto fused_weights = gen_fused_weights(weights, multiplication); + fc->weights(fused_weights); + + // Set origin and copy Activation Function if exisitng: + fc->fusedActivationFunction(mul->fusedActivationFunction()); + luci::add_origin(fc, luci::get_origin(mul)); + + replace(mul).with(fc); + + return true; +} + +} // namespace + +namespace luci +{ + +bool FuseMulWithFullyConnectedPass::run(loco::Graph *g) +{ + bool changed = false; + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + if (auto mul = dynamic_cast(node)) + { + if (fuse_mul_with_fc(mul)) + changed = true; + } + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp new file mode 100644 index 00000000000..a4f9d6bf087 --- /dev/null +++ b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/FuseMulWithFullyConnectedPass.h" +#include "helpers/CreateCircleConst.h" + +#include +#include + +#include + +#define DIM_ONE 8 +#define DIM_TWO 4 +#define MUL_VAL 2.0f + +namespace +{ + +using namespace luci::test; + +/** + * Graph for this test + * + * BEFORE (without extra_fc_successor) + * + * [FC] + * | + * [Mul w/ Relu] + * + * BEFORE (with extra_fc_successor) + * + * [FC] + * | + * |------------------- + * | | + * | | + * [Mul w/ Relu] [other FC] + * + * AFTER (if pass applied) + * + * [FC w/ Relu] (weights and bias updated) + * + */ +class FCMulGraphlet +{ +public: + void init(loco::Graph *g, luci::FusedActFunc fc_activation, bool is_mul_scalar, bool use_bias, + bool extra_successor) + { + _fc = g->nodes()->create(); + + std::vector weights_val(DIM_ONE * DIM_TWO); + for (uint32_t i = 0; i < DIM_ONE * DIM_TWO; i++) + weights_val.at(i) = i; + + _fc_f = luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE, DIM_TWO}, weights_val); + _fc->weights(_fc_f); + + if (use_bias) + { + std::vector bias_val(DIM_ONE); + for (uint32_t i = 0; i < DIM_ONE; i++) + bias_val.at(i) = i; + + _fc_b = luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE}, bias_val); + } + else + { + // Create CircleOutputExclude -- no bias + _fc_b = g->nodes()->create(); + } + _fc->bias(_fc_b); + + _fc->fusedActivationFunction(fc_activation); + _fc->dtype(loco::DataType::FLOAT32); + _fc->shape({1, DIM_ONE}); + _fc->name("fc"); + + if (extra_successor) + { + _extra_succ = g->nodes()->create(); + // Set previous FC as input to bump number of successors for it: + _extra_succ->input(_fc); + std::vector weights_val(DIM_ONE * DIM_TWO); + _extra_f = + luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE, DIM_TWO}, weights_val); + _extra_succ->weights(_extra_f); + _extra_succ->bias(nullptr); + _extra_succ->fusedActivationFunction(luci::FusedActFunc::NONE); + _extra_succ->dtype(loco::DataType::FLOAT32); + _extra_succ->shape({1, DIM_ONE}); + _extra_succ->name("extra_fc"); + } + + std::vector mul_values; + + if (is_mul_scalar) + { + mul_values.push_back(static_cast(MUL_VAL)); + _mul_c = luci::create_const_node(g, loco::DataType::FLOAT32, {}, mul_values); + } + else + { + for (uint32_t i = 0; i < DIM_ONE; i++) + { + mul_values.push_back(static_cast(i)); + } + _mul_c = luci::create_const_node(g, loco::DataType::FLOAT32, {1, 1, 1, DIM_ONE}, mul_values); + } + + _mul = g->nodes()->create(); + _mul->x(_fc); + _mul->y(_mul_c); + _mul->fusedActivationFunction(luci::FusedActFunc::RELU); + _mul->dtype(loco::DataType::FLOAT32); + if (is_mul_scalar) + { + _mul->shape({1, DIM_ONE}); + } + else + { + _mul->shape({1, 1, 1, DIM_ONE}); + } + _mul->name("mul"); + } + +public: + luci::CircleFullyConnected *fc() { return _fc; } + + void to_fm_bias(void) + { + assert(_fc != nullptr); + + auto new_fc = _fc->graph()->nodes()->create(); + _fc->bias(new_fc); + } + +protected: + luci::CircleFullyConnected *_fc = nullptr; + luci::CircleMul *_mul = nullptr; + luci::CircleConst *_fc_f = nullptr; + luci::CircleNode *_fc_b = nullptr; + luci::CircleConst *_mul_c = nullptr; + luci::CircleFullyConnected *_extra_succ = nullptr; + luci::CircleConst *_extra_f = nullptr; +}; + +class FuseMulWithFCTestGraph : public TestIOGraph, public FCMulGraphlet +{ +public: + void init(luci::FusedActFunc fc_activation, bool is_mul_scalar, bool use_bias, + bool extra_successor) + { + TestIOGraph::init({1, DIM_TWO}, {1, DIM_ONE}); + FCMulGraphlet::init(g(), fc_activation, is_mul_scalar, use_bias, extra_successor); + + _fc->input(input()); + + output()->from(_mul); + } +}; + +class FuseMulWithFullyConnectedPassTest : public ::testing::Test +{ +public: + FuseMulWithFCTestGraph g; + luci::FuseMulWithFullyConnectedPass pass; +}; + +} // namespace + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_mul_tensor) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(i * offset, weights->at(offset)); + } + } + + auto bias = loco::must_cast(g.fc()->bias()); + for (uint32_t i = 0; i < bias->size(); i++) + { + EXPECT_EQ(i * i, bias->at(i)); + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_mul_scalar) +{ + g.init(luci::FusedActFunc::NONE, true /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(MUL_VAL * offset, weights->at(offset)); + } + } + + auto bias = loco::must_cast(g.fc()->bias()); + for (uint32_t i = 0; i < bias->size(); i++) + { + EXPECT_EQ(MUL_VAL * i, bias->at(i)); + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_no_bias) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, false /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + auto no_bias = dynamic_cast(fc->bias()); + ASSERT_NE(nullptr, no_bias); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(i * offset, weights->at(offset)); + } + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, bias_feature_map_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + // Bias cannot be fused as it's passed as feature map. + g.to_fm_bias(); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_activation_NEG) +{ + g.init(luci::FusedActFunc::RELU, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_null_weights_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + g.fc()->weights(nullptr); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_extra_successor_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + true /* extra_successor */); + + EXPECT_EQ(false, pass.run(g.g())); +} diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp index 63eb4fb7e37..877bd5a0ae7 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp @@ -568,14 +568,35 @@ loco::NodeShape infer_concatenation(const luci::CircleConcatenation *node) { if (j == static_cast(axis)) { - // If dimension is unknown, value() will return 0. - // This is wrong but until new inference algorithm is implemented, - // this code will not be modified to keep compatibility. - output_shape.dim(j) = output_shape.dim(j).value() + input_shape.dim(j).value(); + if (output_shape.dim(j).known() and input_shape.dim(j).known()) + { + output_shape.dim(j) = output_shape.dim(j).value() + input_shape.dim(j).value(); + } + else + { + // If any of inputs is unknown, just mark it as unknown. + output_shape.dim(j).unset(); + } } else - assert(!output_shape.dim(j).known() || !input_shape.dim(j).known() || - output_shape.dim(j) == input_shape.dim(j)); + { + if (output_shape.dim(j).known() and input_shape.dim(j).known()) + { + if (output_shape.dim(j).value() != input_shape.dim(j).value()) + { + INTERNAL_EXN_V("Input has incompatible shape.", node->name()); + } + } + else + { + if (input_shape.dim(j).known()) + { + assert(not output_shape.dim(j).known()); // FIX_ME_UNLESS + output_shape.dim(j) = input_shape.dim(j); + } + // For unknown input_shape, leave output_shape as-is + } + } } } diff --git a/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp b/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp index 270068cf0d9..7bf0268c9f4 100644 --- a/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp +++ b/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp @@ -16,6 +16,8 @@ #include "luci/Service/CircleNodeClone.h" +#include + #include TEST(CloneNodeTest, clone_Concatenation) @@ -47,3 +49,112 @@ TEST(CloneNodeTest, clone_Concatenation_NEG) auto cloned = luci::clone_node(node_concat, gc.get()); ASSERT_EQ(nullptr, cloned); } + +TEST(ShapeRuleTest, concat_dynamic_shape_axis) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(2); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + ASSERT_TRUE(shape_inf_rule.infer(&concat, shape)); + ASSERT_EQ(4, shape.rank()); + ASSERT_TRUE(shape.dim(0).known()); + ASSERT_TRUE(shape.dim(1).known()); + ASSERT_FALSE(shape.dim(2).known()); + ASSERT_TRUE(shape.dim(3).known()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(4, shape.dim(1).value()); + ASSERT_EQ(0, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); +} + +TEST(ShapeRuleTest, concat_dynamic_shape_non_axis) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(1); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + ASSERT_TRUE(shape_inf_rule.infer(&concat, shape)); + ASSERT_EQ(4, shape.rank()); + ASSERT_TRUE(shape.dim(0).known()); + ASSERT_TRUE(shape.dim(1).known()); + ASSERT_TRUE(shape.dim(2).known()); + ASSERT_TRUE(shape.dim(3).known()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(8, shape.dim(1).value()); + ASSERT_EQ(3, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); +} + +TEST(ShapeRuleTest, concat_wrong_shape_NEG) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 4, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(1); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + EXPECT_ANY_THROW(shape_inf_rule.infer(&concat, shape)); +} + +TEST(ShapeRuleTest, concat_rank_mismatch_NEG) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(2); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + EXPECT_ANY_THROW(shape_inf_rule.infer(&concat, shape)); +} diff --git a/compiler/luci/tester/src/WriteTester.cpp b/compiler/luci/tester/src/WriteTester.cpp index 0d3a1efa220..e5b31e16dc6 100644 --- a/compiler/luci/tester/src/WriteTester.cpp +++ b/compiler/luci/tester/src/WriteTester.cpp @@ -42,11 +42,6 @@ void show_error_message(const char *progname, std::ostream &os, const std::strin struct CircleExpContract : public luci::CircleExporter::Contract { public: - CircleExpContract(loco::Graph *graph, const std::string &filename) - : _graph(graph), _filepath(filename) - { - // NOTHING TO DO - } CircleExpContract(luci::Module *module, const std::string &filename) : _module(module), _filepath(filename) { @@ -55,15 +50,12 @@ struct CircleExpContract : public luci::CircleExporter::Contract virtual ~CircleExpContract() = default; public: - loco::Graph *graph(void) const final { return _graph; } - luci::Module *module(void) const final { return _module; } public: bool store(const char *ptr, const size_t size) const final; private: - loco::Graph *_graph{nullptr}; luci::Module *_module{nullptr}; const std::string _filepath; }; diff --git a/compiler/mio-circle08/CMakeLists.txt b/compiler/mio-circle08/CMakeLists.txt index 03e449d6e81..cee15c96993 100644 --- a/compiler/mio-circle08/CMakeLists.txt +++ b/compiler/mio-circle08/CMakeLists.txt @@ -19,7 +19,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" DEPENDS "${SCHEMA_FILE}" ) -FlatBuffers_Target(mio_circle08 +FlatBuffersMuteable_Target(mio_circle08 OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/mio/circle" INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen" SCHEMA_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/compiler/mio-circle08/include/mio_circle/Reader.h b/compiler/mio-circle08/include/mio_circle/Reader.h index 723668f264e..079ef27b77f 100644 --- a/compiler/mio-circle08/include/mio_circle/Reader.h +++ b/compiler/mio-circle08/include/mio_circle/Reader.h @@ -47,6 +47,7 @@ class Reader public: Reader(const ::circle::Model *model); + Reader(const ::circle::Model *model, const std::vector *rawdata); Reader() = delete; @@ -65,6 +66,7 @@ class Reader uint32_t num_subgraph() const { return _subgraphs->size(); } size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data); + size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset); ::circle::BuiltinOperator builtin_code(const ::circle::Operator *op) const; std::string opcode_name(const ::circle::Operator *op) const; std::vector outputs(const ::circle::Operator *op) const; @@ -79,6 +81,8 @@ class Reader private: uint32_t _version; + const std::vector *_rawdata{nullptr}; + const CircleSubGraphs_t *_subgraphs{nullptr}; const CircleBuffers_t *_buffers{nullptr}; const CircleTensors_t *_tensors{nullptr}; diff --git a/compiler/mio-circle08/src/Reader.cpp b/compiler/mio-circle08/src/Reader.cpp index e4df6d04d54..b9f17725e01 100644 --- a/compiler/mio-circle08/src/Reader.cpp +++ b/compiler/mio-circle08/src/Reader.cpp @@ -17,6 +17,7 @@ #include "mio_circle/Reader.h" #include "mio_circle/Helper.h" +#include #include #include @@ -45,6 +46,28 @@ Reader::Reader(const ::circle::Model *model) } } +Reader::Reader(const ::circle::Model *model, const std::vector *rawdata) +{ + if (model == nullptr) + { + throw std::runtime_error("Invalid model"); + } + + _rawdata = rawdata; + + _version = model->version(); + _subgraphs = model->subgraphs(); + _buffers = model->buffers(); + _metadata = model->metadata(); + _signature_defs = model->signature_defs(); + + auto opcodes = model->operator_codes(); + for (const ::circle::OperatorCode *opcode : *opcodes) + { + _op_codes.push_back(opcode); + } +} + size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) { if (buff_data != nullptr) @@ -73,6 +96,54 @@ size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) return 0; } +size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset) +{ + ext_offset = false; + + if (buff_data != nullptr) + { + *buff_data = nullptr; + } + + if (buf_idx == 0) + return 0; + + if (auto *buffer = (*_buffers)[buf_idx]) + { + auto buffer_offset = buffer->offset(); + if (buffer_offset > 1) + { + assert(_rawdata); // make debug break for invalid case + if (_rawdata == nullptr) + return 0; + + ext_offset = true; + *buff_data = reinterpret_cast(&_rawdata->at(buffer_offset)); + return buffer->size(); + } + else if (auto *array = buffer->data()) + { + if (size_t size = array->size()) + { + if (buff_data != nullptr) + { + *buff_data = reinterpret_cast(array->data()); + } + return size; + } + } + else + { + if (buffer->offset() == 1 && buffer->size() == 1) + { + std::cerr << "Buffer " << buf_idx << " has invalid offset/size." << std::endl; + } + } + } + + return 0; +} + ::circle::BuiltinOperator Reader::builtin_code(const ::circle::Operator *op) const { uint32_t index = op->opcode_index(); diff --git a/compiler/mio-tflite2121/CMakeLists.txt b/compiler/mio-tflite2121/CMakeLists.txt index 371118be83c..3cd9662d460 100644 --- a/compiler/mio-tflite2121/CMakeLists.txt +++ b/compiler/mio-tflite2121/CMakeLists.txt @@ -15,7 +15,9 @@ endif(NOT TensorFlowSource_FOUND) message(STATUS "Build mio-tflite2121: TRUE") message(STATUS "Build mio-tflite2121: with ${TensorFlowSource_DIR}") -set(SCHEMA_FILE "${TensorFlowSource_DIR}/tensorflow/lite/schema/schema.fbs") +# TODO rollback to use TensorFlowSource_DIR after upgrade +#set(SCHEMA_FILE "${TensorFlowSource_DIR}/tensorflow/lite/schema/schema.fbs") +set(SCHEMA_FILE "${NNAS_PROJECT_SOURCE_DIR}/res/TensorFlowLiteSchema/2.16.1/schema.fbs") # NOTE Use copy of schema.fbs as to provide unified way for circle also add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" @@ -24,7 +26,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" DEPENDS "${SCHEMA_FILE}" ) -FlatBuffers_Target(mio_tflite2121 +FlatBuffersMuteable_Target(mio_tflite2121 OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/mio/tflite" INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen" SCHEMA_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 4025ed2306f..af7255195dc 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -47,38 +47,6 @@ using namespace souschef; namespace { -class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl -{ -public: - GeneratedModelImpl(std::unique_ptr &&builder) - : _builder{std::move(builder)} - { - // DO NOTHING - } - -public: - const char *base(void) const override - { - // Return the base address of generated flatbuffer model - return reinterpret_cast(_builder->GetBufferPointer()); - } - -public: - size_t size(void) const override - { - // Return the size of generated flatbuffer model - return _builder->GetSize(); - } - -private: - std::unique_ptr _builder; -}; - -} // namespace - -namespace -{ - struct DataChefRegistry final : public Registry { }; @@ -209,17 +177,67 @@ std::set gather_customcode_set(const ::tflchef::ModelRecipe &model_ namespace { -struct CookParams +class ModelChef { - std::vector> &buffer_vec; - std::vector> &code_vec; - std::vector> &subgraph_vec; - std::unique_ptr &flatbuffer_builder; - std::map &builtin_code_map; - std::vector &custom_code_vec; - std::string noname; +public: + ModelChef() = default; + +public: + void init(void); + void cook(const ::tflchef::ModelRecipe &model_recipe); + +private: + void prepare_initial_buffer(void); + void gather_operator_codes(const ::tflchef::ModelRecipe &model_recipe); + void gather_signature_defs(const ::tflchef::ModelRecipe &model_recipe); + + template void cook_operands(const T &graph); + + template + void cook_operations(const T &graph, std::map &symbol_table); + + template + void cook_graph(const T &graph, std::map &symbol_table); + + bool finalize_ext_buffer(void); + +public: + const char *get_buffer_pointer(void) const; + size_t get_size(void) const; + +private: + std::unique_ptr _flatbuffer_builder; + + std::vector> _signdef_vec; + std::vector> _buffer_vec; + std::vector> _code_vec; + std::vector> _subgraph_vec; + std::map _builtin_code_map; + std::vector _custom_code_vec; + // _symbol_tables stores symbol_table of each sub graph + // this is used to find tensor ID(index) with tensor name + std::vector> _symbol_tables; + + // per graph that needs clear afer graph is processed + // Operand-related + std::vector> _tensor_vec; + // Operation-related + std::vector> _operator_vec; + + std::string _graph_name; + + // store Buffer data to external of FB and use (Buffer) offset/size fields + bool _ext_offset = false; + std::map> _buffer_data_map; + std::string _ext_data; }; +void ModelChef::init(void) +{ + _flatbuffer_builder = + std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); +} + std::vector> make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_t dims_count, const std::vector &traversal_order_vec, @@ -255,59 +273,24 @@ make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_ return dim_metadata_vec; } -template std::map cook_graph(const T &graph, CookParams &cp) +template void ModelChef::cook_operands(const T &graph) { - LOGGER(l); - - std::vector> &buffer_vec = cp.buffer_vec; - std::vector> &code_vec = cp.code_vec; - std::vector> &subgraph_vec = cp.subgraph_vec; - std::unique_ptr &flatbuffer_builder = cp.flatbuffer_builder; - std::map &builtin_code_map = cp.builtin_code_map; - std::vector &custom_code_vec = cp.custom_code_vec; - - // Operand-related - std::vector> tensor_vec; - - // Operation-related - std::vector> operator_vec; - - // default name for graph - std::string graph_name = cp.noname; - if (graph.has_name()) - graph_name = graph.name(); - - // Tensor Name -> Tensor ID mapping (per Graph) - std::map symbol_table; - - auto lookup = [&symbol_table, &graph_name](const std::string &name) { - if (symbol_table.find(name) != symbol_table.end()) - return symbol_table.at(name); - else if (name == "") - return -1; // -1 in TFLite means that optional input tensor is empty. - else - { - std::string msg = "tflchef : input not found in " + graph_name + " graph"; - throw std::runtime_error(msg.c_str()); - } - }; - - int32_t buffer_start = buffer_vec.size(); + int32_t buffer_start = _buffer_vec.size(); int32_t buffer_index = 0; // Create buffer(s) 1~n(I) for input(s) const auto size_input = graph.input_size(); for (int ci = 0; ci < size_input; ++ci) { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } // Create buffer(s) n(I)+1~n(I)+n(O) for output(s) const auto size_output = graph.output_size(); for (int co = 0; co < size_output; ++co) { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } auto input_names = as_dataset(graph.input()).vectorize(); @@ -316,7 +299,6 @@ template std::map cook_graph(const T &graph, for (const auto &operand : graph.operand()) { assert(operand.has_name()); - assert(operand.has_type()); flatbuffers::Offset sparsity_index; @@ -326,10 +308,10 @@ template std::map cook_graph(const T &graph, if (operand.has_shape()) { dims = as_dims(operand.shape()); - shape = flatbuffer_builder->CreateVector(dims); + shape = _flatbuffer_builder->CreateVector(dims); } - auto name = flatbuffer_builder->CreateString(operand.name()); + auto name = _flatbuffer_builder->CreateString(operand.name()); buffer_index = 0; @@ -380,31 +362,41 @@ template std::map cook_graph(const T &graph, sparse_uint8.emplace_back(arr[b]); } } - auto data = flatbuffer_builder->CreateVector(sparse_uint8); - - // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = sparse_uint8; - // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } // save SparsityParameters - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata const auto &dim_metadata_src = converter.GetDimMetadata(); auto dim_metadata_vec = - make_dim_metadata_vec(flatbuffer_builder.get(), dims_count, traversal_order_vec, + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, format_vec, dim_metadata_src); - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } else if (operand.type() == tflchef::FLOAT16) @@ -423,31 +415,42 @@ template std::map cook_graph(const T &graph, sparse_uint8.emplace_back(arr[b]); } } - auto data = flatbuffer_builder->CreateVector(sparse_uint8); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = sparse_uint8; - // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); - // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } // save SparsityParameters - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata const auto &dim_metadata_src = converter.GetDimMetadata(); auto dim_metadata_vec = - make_dim_metadata_vec(flatbuffer_builder.get(), dims_count, traversal_order_vec, + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, format_vec, dim_metadata_src); - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } else @@ -472,16 +475,27 @@ template std::map cook_graph(const T &graph, data_vec = data_packed; } - auto data = flatbuffer_builder->CreateVector(data_vec); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = data_vec; + + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(data_vec); - // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); - // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } } } else @@ -511,10 +525,10 @@ template std::map cook_graph(const T &graph, if (buffer_index == 0) { // we couldn't find the buffer; create an empty buffer for this tensor - buffer_index = buffer_vec.size(); + buffer_index = _buffer_vec.size(); - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } } assert(buffer_index != 0); @@ -542,13 +556,13 @@ template std::map cook_graph(const T &graph, for (uint32_t i = 0; i < quant.zero_point_size(); ++i) quant_zero_point_vec.at(i) = quant.zero_point(i); - auto quant_max = flatbuffer_builder->CreateVector(quant_max_vec); - auto quant_min = flatbuffer_builder->CreateVector(quant_min_vec); - auto quant_scale = flatbuffer_builder->CreateVector(quant_scale_vec); - auto quant_zero_point = flatbuffer_builder->CreateVector(quant_zero_point_vec); + auto quant_max = _flatbuffer_builder->CreateVector(quant_max_vec); + auto quant_min = _flatbuffer_builder->CreateVector(quant_min_vec); + auto quant_scale = _flatbuffer_builder->CreateVector(quant_scale_vec); + auto quant_zero_point = _flatbuffer_builder->CreateVector(quant_zero_point_vec); // Create QuantizationParameters - tflite::QuantizationParametersBuilder quant_builder{*flatbuffer_builder}; + tflite::QuantizationParametersBuilder quant_builder{*_flatbuffer_builder}; quant_builder.add_max(quant_max); quant_builder.add_min(quant_min); quant_builder.add_scale(quant_scale); @@ -566,12 +580,12 @@ template std::map cook_graph(const T &graph, // Create traversal order std::vector traversal_order_vec{sparsity.traversal_order().dim().begin(), sparsity.traversal_order().dim().end()}; - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{sparsity.block_map().dim().begin(), sparsity.block_map().dim().end()}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata std::vector> dim_metadata_vec; @@ -580,13 +594,13 @@ template std::map cook_graph(const T &graph, { // Create array segments auto tflite_array_segments = - as_tflite_sparse_index_vec(*flatbuffer_builder, dm.array_segments()); + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_segments()); // Create array indices auto tflite_array_indices = - as_tflite_sparse_index_vec(*flatbuffer_builder, dm.array_indices()); + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_indices()); - auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*flatbuffer_builder}; + auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*_flatbuffer_builder}; tflite_dim_metadata_builder.add_format(as_tflite_dimensiontype(dm.format())); tflite_dim_metadata_builder.add_dense_size(dm.dense_size()); tflite_dim_metadata_builder.add_array_segments(tflite_array_segments); @@ -598,9 +612,9 @@ template std::map cook_graph(const T &graph, auto tflite_dim_metadata = tflite_dim_metadata_builder.Finish(); dim_metadata_vec.emplace_back(tflite_dim_metadata); } - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } @@ -608,11 +622,11 @@ template std::map cook_graph(const T &graph, if (operand.has_shape_signature()) { auto signature = as_dims(operand.shape_signature()); - shape_signature = flatbuffer_builder->CreateVector(signature); + shape_signature = _flatbuffer_builder->CreateVector(signature); } // Create Tensor - tflite::TensorBuilder tensor_builder{*flatbuffer_builder}; + tflite::TensorBuilder tensor_builder{*_flatbuffer_builder}; tensor_builder.add_shape(shape); tensor_builder.add_type(as_tflite_tensortype(operand.type())); @@ -626,16 +640,24 @@ template std::map cook_graph(const T &graph, tensor_builder.add_shape_signature(shape_signature); // Append! - tensor_vec.emplace_back(tensor_builder.Finish()); - - // Update Tensor Name -> Tensor Index Map - int32_t tensor_index = symbol_table.size(); - const auto &tensor_name = operand.name(); - - INFO(l) << "Symbol [" << tensor_name << "] = Tensor " << tensor_index << std::endl; - - symbol_table[tensor_name] = tensor_index; + _tensor_vec.emplace_back(tensor_builder.Finish()); } +} + +template +void ModelChef::cook_operations(const T &graph, std::map &symbol_table) +{ + auto lookup = [&](const std::string &name) { + if (symbol_table.find(name) != symbol_table.end()) + return symbol_table.at(name); + else if (name == "") + return -1; // -1 in TFLite means that optional input tensor is empty. + else + { + std::string msg = "tflchef : input not found in " + _graph_name + " graph"; + throw std::runtime_error(msg.c_str()); + } + }; // Create Operator for (const auto &operation : graph.operation()) @@ -650,39 +672,39 @@ template std::map cook_graph(const T &graph, // Create 'inputs' std::vector input_vec = as_dataset(operation.input()).map(lookup).vectorize(); - auto inputs = flatbuffer_builder->CreateVector(input_vec); + auto inputs = _flatbuffer_builder->CreateVector(input_vec); // Create 'outputs' std::vector output_vec = as_dataset(operation.output()).map(lookup).vectorize(); - auto outputs = flatbuffer_builder->CreateVector(output_vec); + auto outputs = _flatbuffer_builder->CreateVector(output_vec); // Create Option - auto options = op_chef->value(*flatbuffer_builder); + auto options = op_chef->value(*_flatbuffer_builder); // Create Custom option - auto circle_custom_options = op_chef->custom_value(*flatbuffer_builder); + auto circle_custom_options = op_chef->custom_value(*_flatbuffer_builder); // Create Operator - tflite::OperatorBuilder op_builder{*flatbuffer_builder}; + tflite::OperatorBuilder op_builder{*_flatbuffer_builder}; // Note that opcode_index is an index into the operator_codes vector. // operator_codes consists of buildtin_code and custom_code, which is inserted sequentially. uint32_t opcode_index = 0; - auto op_it = builtin_code_map.find(op_chef->code()); + auto op_it = _builtin_code_map.find(op_chef->code()); // builtin operator - if (op_it != builtin_code_map.end()) + if (op_it != _builtin_code_map.end()) { - opcode_index = std::distance(builtin_code_map.begin(), op_it); + opcode_index = std::distance(_builtin_code_map.begin(), op_it); } // custom operator else { assert(not operation.custom_code().empty()); auto custom_code = operation.custom_code(); - auto op_it = std::find(custom_code_vec.begin(), custom_code_vec.end(), custom_code); - assert(op_it != custom_code_vec.end()); - opcode_index = builtin_code_map.size(); - opcode_index += std::distance(custom_code_vec.begin(), op_it); + auto op_it = std::find(_custom_code_vec.begin(), _custom_code_vec.end(), custom_code); + assert(op_it != _custom_code_vec.end()); + opcode_index = _builtin_code_map.size(); + opcode_index += std::distance(_custom_code_vec.begin(), op_it); } op_builder.add_opcode_index(opcode_index); @@ -693,21 +715,62 @@ template std::map cook_graph(const T &graph, op_builder.add_custom_options(circle_custom_options); op_builder.add_custom_options_format(tflite::CustomOptionsFormat_FLEXBUFFERS); // Append Operator - operator_vec.emplace_back(op_builder.Finish()); + _operator_vec.emplace_back(op_builder.Finish()); } +} + +template +void ModelChef::cook_graph(const T &graph, std::map &symbol_table) +{ + LOGGER(l); + + assert(symbol_table.empty()); // FIX_CALLER_UNLESS + assert(_tensor_vec.empty()); // FIX_CALLER_UNLESS + assert(_operator_vec.empty()); // FIX_CALLER_UNLESS + + // default name for graph + if (graph.has_name()) + _graph_name = graph.name(); + + auto lookup = [&](const std::string &name) { + if (symbol_table.find(name) != symbol_table.end()) + return symbol_table.at(name); + else if (name == "") + return -1; // -1 in TFLite means that optional input tensor is empty. + else + { + std::string msg = "tflchef : input not found in " + _graph_name + " graph"; + throw std::runtime_error(msg.c_str()); + } + }; + + cook_operands(graph); + + for (const auto &operand : graph.operand()) + { + // Update Tensor Name -> Tensor Index Map + int32_t tensor_index = symbol_table.size(); + const auto &tensor_name = operand.name(); + + INFO(l) << "Symbol [" << tensor_name << "] = Tensor " << tensor_index << std::endl; + + symbol_table[tensor_name] = tensor_index; + } + + cook_operations(graph, symbol_table); // Create network input/output vector std::vector input_vec = as_dataset(graph.input()).map(lookup).vectorize(); std::vector output_vec = as_dataset(graph.output()).map(lookup).vectorize(); // Create "SubGraph" arguments - auto tensors = flatbuffer_builder->CreateVector(tensor_vec); - auto inputs = flatbuffer_builder->CreateVector(input_vec); - auto outputs = flatbuffer_builder->CreateVector(output_vec); - auto operators = flatbuffer_builder->CreateVector(operator_vec); - auto name = flatbuffer_builder->CreateString(graph_name); + auto tensors = _flatbuffer_builder->CreateVector(_tensor_vec); + auto inputs = _flatbuffer_builder->CreateVector(input_vec); + auto outputs = _flatbuffer_builder->CreateVector(output_vec); + auto operators = _flatbuffer_builder->CreateVector(_operator_vec); + auto name = _flatbuffer_builder->CreateString(_graph_name); - tflite::SubGraphBuilder subgraph_builder{*flatbuffer_builder}; + tflite::SubGraphBuilder subgraph_builder{*_flatbuffer_builder}; subgraph_builder.add_tensors(tensors); subgraph_builder.add_inputs(inputs); @@ -715,57 +778,16 @@ template std::map cook_graph(const T &graph, subgraph_builder.add_operators(operators); subgraph_builder.add_name(name); - subgraph_vec.emplace_back(subgraph_builder.Finish()); - - return symbol_table; + _subgraph_vec.emplace_back(subgraph_builder.Finish()); } -} // namespace - -namespace tflchef +void ModelChef::gather_operator_codes(const ::tflchef::ModelRecipe &model_recipe) { - -/** - * @brief Generate a (in-memory) TensorFlow Lite model from a given model recipe - */ -GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) -{ -// Initialize Op Chef Registry -#define OP_CHEF(NAME, FACTORY_CLASS) \ - op_chef_registry().add(#NAME, std::unique_ptr(new FACTORY_CLASS())); -#include "OpChef.def" -#undef OP_CHEF - -// Initialize Data Chef Registry -#define DATA_CHEF(TYPE, NAME, FACTORY_CLASS) \ - data_chef_registry(::tflchef::TYPE) \ - .add(#NAME, std::unique_ptr(new FACTORY_CLASS())); -#include "DataChef.def" -#undef DATA_CHEF - - // - // Create FlatBufferBuilder - // - auto flatbuffer_builder = - std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); - - // Operand-related - std::vector> buffer_vec; - - // Operation-related - std::vector> code_vec; - - // SignatureDef-related - std::vector> signdef_vec; - - // Graphs-related - std::vector> subgraph_vec; - // Create OperatorCode with Builtin Operator - auto builtin_code_map = gather_builtincode_map(model_recipe); - for (auto const &opcode : builtin_code_map) + _builtin_code_map = gather_builtincode_map(model_recipe); + for (auto const &opcode : _builtin_code_map) { - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES // This is the way to handle deprecated builtin code // See @@ -783,66 +805,41 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) code_builder.add_builtin_code(opcode.first); auto code = code_builder.Finish(); // Update OperatorCode vector - code_vec.emplace_back(code); + _code_vec.emplace_back(code); } // Create OperatorCode with Custom Operator - std::set custom_code_set = gather_customcode_set(model_recipe); - std::vector custom_code_vec{custom_code_set.begin(), custom_code_set.end()}; + { + std::set custom_code_set = gather_customcode_set(model_recipe); + std::vector custom_code_vec{custom_code_set.begin(), custom_code_set.end()}; + _custom_code_vec = custom_code_vec; + } - for (auto opcode : custom_code_vec) + for (auto opcode : _custom_code_vec) { - auto custom_code = flatbuffer_builder->CreateString(opcode); - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + auto custom_code = _flatbuffer_builder->CreateString(opcode); + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); code_builder.add_custom_code(custom_code); code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); auto code = code_builder.Finish(); // Update OperatorCode vector - code_vec.emplace_back(code); + _code_vec.emplace_back(code); } +} +void ModelChef::prepare_initial_buffer(void) +{ // Create an Empty Buffer // // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file // (Please refer to the comment for Tensor.buffer field in schema) - { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); - } - - // symbol_tables stores symbol_table of each sub graph - // this is used to find tensor ID(index) with tensor name - std::vector> symbol_tables; - - // - // Create Main graph - // - CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, - builtin_code_map, custom_code_vec, "main"}; - - auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe, cp); - symbol_tables.push_back(table); - - // - // Create subgraphs if exist - // - for (int g = 0; g < model_recipe.graph_size(); ++g) - { - const auto &graph = model_recipe.graph(g); - - std::ostringstream stringStream; - stringStream << "sub_" << (g + 1); - - CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, - builtin_code_map, custom_code_vec, stringStream.str()}; - - auto table = cook_graph<::tflchef::Graph>(graph, cp); - symbol_tables.push_back(table); - } + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); +} - // Create Signature-Def - // +void ModelChef::gather_signature_defs(const ::tflchef::ModelRecipe &model_recipe) +{ for (int s = 0; s < model_recipe.signature_def_size(); ++s) { // load from recipe @@ -857,15 +854,15 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) { subgraph_index = rec_signature_def.subgraph_index(); } - assert(subgraph_index < symbol_tables.size()); - auto &symbol_table = symbol_tables[subgraph_index]; + assert(subgraph_index < _symbol_tables.size()); + auto &symbol_table = _symbol_tables[subgraph_index]; // cook for inputs for (int si = 0; si < rec_signature_def.inputs_size(); ++si) { // recipe for input TensorMap auto rec_tm_input = rec_signature_def.inputs(si); - auto name = flatbuffer_builder->CreateString(rec_tm_input.name()); + auto name = _flatbuffer_builder->CreateString(rec_tm_input.name()); uint32_t tensor_index = 0; // either tensor or tensor_index should exist assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); @@ -881,7 +878,7 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) tensor_index = rec_tm_input.tensor_index(); } - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; tensormap_builder.add_name(name); tensormap_builder.add_tensor_index(tensor_index); tensormap_inputs.push_back(tensormap_builder.Finish()); @@ -890,7 +887,7 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) for (int so = 0; so < rec_signature_def.outputs_size(); ++so) { auto rec_tm_output = rec_signature_def.outputs(so); - auto name = flatbuffer_builder->CreateString(rec_tm_output.name()); + auto name = _flatbuffer_builder->CreateString(rec_tm_output.name()); uint32_t tensor_index = 0; assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); if (rec_tm_output.has_tensor()) @@ -903,35 +900,136 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) tensor_index = rec_tm_output.tensor_index(); } - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; tensormap_builder.add_name(name); tensormap_builder.add_tensor_index(tensor_index); tensormap_outputs.push_back(tensormap_builder.Finish()); } - auto inputs = flatbuffer_builder->CreateVector(tensormap_inputs); - auto outputs = flatbuffer_builder->CreateVector(tensormap_outputs); - auto signature_key = flatbuffer_builder->CreateString(rec_signature_def.signature_key()); + auto inputs = _flatbuffer_builder->CreateVector(tensormap_inputs); + auto outputs = _flatbuffer_builder->CreateVector(tensormap_outputs); + auto signature_key = _flatbuffer_builder->CreateString(rec_signature_def.signature_key()); // TODO add validation for signature_key - ::tflite::SignatureDefBuilder signature_def_builder{*flatbuffer_builder}; + ::tflite::SignatureDefBuilder signature_def_builder{*_flatbuffer_builder}; signature_def_builder.add_inputs(inputs); signature_def_builder.add_outputs(outputs); signature_def_builder.add_signature_key(signature_key); signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); - signdef_vec.emplace_back(signature_def_builder.Finish()); + _signdef_vec.emplace_back(signature_def_builder.Finish()); } +} + +bool ModelChef::finalize_ext_buffer(void) +{ + // NOTE modification of std::string object in the middle may reallocate it. + // we will use std::string::reserve() to prevent this. + + auto align16 = [](size_t &v) { + while (v % 16 != 0) + v++; + }; + + // get total memory for flatbuffer + all buffer_data + size_t result_size = _flatbuffer_builder->GetSize(); + align16(result_size); + for (auto &it : _buffer_data_map) + { + std::vector &buffer_data = it.second; + result_size += buffer_data.size(); + align16(result_size); + } + align16(result_size); + result_size += 16; // additional for safety + + std::string result; + auto *buff_ptr = reinterpret_cast(_flatbuffer_builder->GetBufferPointer()); + + auto padalign16 = [](std::string &str) { + while (str.size() % 16 != 0) + str += '\0'; + }; + + result.reserve(result_size); + result.append(buff_ptr, _flatbuffer_builder->GetSize()); + + auto mutable_model = tflite::GetMutableModel(result.data()); + auto mutable_buffers = mutable_model->mutable_buffers(); + bool ret = true; + + padalign16(result); + for (auto &it : _buffer_data_map) + { + int32_t buffer_index = it.first; + std::vector &buffer_data = it.second; + uint64_t offset = result.size(); + uint64_t size = buffer_data.size(); + + tflite::Buffer *mutable_buffer = mutable_buffers->GetMutableObject(buffer_index); + ret &= mutable_buffer->mutate_offset(offset); + ret &= mutable_buffer->mutate_size(size); + + result.append(buffer_data.begin(), buffer_data.end()); + padalign16(result); + } + padalign16(result); + + // use final result + _ext_data = result; + + return ret; +} + +void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) +{ + // use Custom/Buffer offset + _ext_offset = model_recipe.has_ext_offset() ? model_recipe.ext_offset() : false; + + prepare_initial_buffer(); + + gather_operator_codes(model_recipe); + + // + // Create Main graph + // + + _graph_name = "main"; + // Tensor Name -> Tensor ID mapping (per Graph) + std::map symbol_table; + cook_graph<::tflchef::ModelRecipe>(model_recipe, symbol_table); + _symbol_tables.push_back(symbol_table); + + // + // Create subgraphs if exist + // + for (int g = 0; g < model_recipe.graph_size(); ++g) + { + const auto &graph = model_recipe.graph(g); + + std::ostringstream stringStream; + stringStream << "sub_" << (g + 1); + + _graph_name = stringStream.str(); + + symbol_table.clear(); + _tensor_vec.clear(); + _operator_vec.clear(); + cook_graph<::tflchef::Graph>(graph, symbol_table); + _symbol_tables.push_back(symbol_table); + } + + gather_signature_defs(model_recipe); // Create "Model" arguments - auto buffers = flatbuffer_builder->CreateVector(buffer_vec); - auto signdefs = flatbuffer_builder->CreateVector(signdef_vec); - auto operator_codes = flatbuffer_builder->CreateVector(code_vec); - auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec); - auto description = flatbuffer_builder->CreateString("Generated by tflchef"); + auto buffers = _flatbuffer_builder->CreateVector(_buffer_vec); + auto signdefs = _flatbuffer_builder->CreateVector(_signdef_vec); + auto operator_codes = _flatbuffer_builder->CreateVector(_code_vec); + auto subgraphs = _flatbuffer_builder->CreateVector(_subgraph_vec); + auto description = _flatbuffer_builder->CreateString("Generated by tflchef"); // Create "Model" - tflite::ModelBuilder model_builder{*flatbuffer_builder}; + tflite::ModelBuilder model_builder{*_flatbuffer_builder}; model_builder.add_version(3); model_builder.add_operator_codes(operator_codes); @@ -943,11 +1041,83 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) auto model = model_builder.Finish(); // Finalize - ::tflite::FinishModelBuffer(*flatbuffer_builder, model); + ::tflite::FinishModelBuffer(*_flatbuffer_builder, model); + + if (_ext_offset) + finalize_ext_buffer(); +} + +const char *ModelChef::get_buffer_pointer(void) const +{ + if (_ext_offset) + return _ext_data.data(); + return reinterpret_cast(_flatbuffer_builder->GetBufferPointer()); +} + +size_t ModelChef::get_size(void) const +{ + if (_ext_offset) + return _ext_data.size(); + return _flatbuffer_builder->GetSize(); +} + +} // namespace + +namespace +{ + +class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl +{ +public: + GeneratedModelImpl() + { + // DO NOTHING + } + +public: + const char *base(void) const override { return _mc.get_buffer_pointer(); } + + size_t size(void) const override { return _mc.get_size(); } + +public: + ModelChef &model_chef(void) { return _mc; } + +private: + ModelChef _mc; +}; + +} // namespace + +namespace tflchef +{ + +/** + * @brief Generate a (in-memory) TensorFlow Lite model from a given model recipe + */ +GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) +{ +// Initialize Op Chef Registry +#define OP_CHEF(NAME, FACTORY_CLASS) \ + op_chef_registry().add(#NAME, std::unique_ptr(new FACTORY_CLASS())); +#include "OpChef.def" +#undef OP_CHEF + +// Initialize Data Chef Registry +#define DATA_CHEF(TYPE, NAME, FACTORY_CLASS) \ + data_chef_registry(::tflchef::TYPE) \ + .add(#NAME, std::unique_ptr(new FACTORY_CLASS())); +#include "DataChef.def" +#undef DATA_CHEF + + std::unique_ptr gen_model(new GeneratedModelImpl()); + + ModelChef &mc = gen_model->model_chef(); + + mc.init(); + mc.cook(model_recipe); // Return "GenerateModel" - return GeneratedModel{ - std::unique_ptr(new GeneratedModelImpl(std::move(flatbuffer_builder)))}; + return GeneratedModel{std::move(gen_model)}; } } // namespace tflchef diff --git a/compiler/tflchef/proto/tflchef.proto b/compiler/tflchef/proto/tflchef.proto index e4ae5d9b65b..59995f13e71 100644 --- a/compiler/tflchef/proto/tflchef.proto +++ b/compiler/tflchef/proto/tflchef.proto @@ -719,4 +719,6 @@ message ModelRecipe { optional uint32 version = 6 [default = 1]; repeated Graph graph = 7; repeated SignatureDef signature_def = 8; + // store to external and use (Buffer) offset + optional bool ext_offset = 9 [default = false]; } diff --git a/compiler/tflchef/tests/ext_offset/test.recipe b/compiler/tflchef/tests/ext_offset/test.recipe new file mode 100644 index 00000000000..fb94e9c7b26 --- /dev/null +++ b/compiler/tflchef/tests/ext_offset/test.recipe @@ -0,0 +1,44 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 3 dim: 3 dim: 2 } +} +operand { + name: "ker" + type: FLOAT32 + shape { dim: 1 dim: 1 dim: 1 dim: 2 } + filler { + tag: "explicit" + arg: "1.1" + arg: "2.2" + } +} +operand { + name: "bias" + type: FLOAT32 + shape { dim: 1 } + filler { + tag: "constant" + arg: "3.3" + } +} +operand { + name: "ofm" + type: FLOAT32 + shape { dim: 1 dim: 3 dim: 3 dim: 1 } +} +operation { + type: "Conv2D" + conv2d_options { + padding: VALID + stride_w: 1 + stride_h: 1 + } + input: "ifm" + input: "ker" + input: "bias" + output: "ofm" +} +input: "ifm" +output: "ofm" +ext_offset: true diff --git a/compiler/tfldump/driver/Driver.cpp b/compiler/tfldump/driver/Driver.cpp index a3e748be1d1..1fb5725a6de 100644 --- a/compiler/tfldump/driver/Driver.cpp +++ b/compiler/tfldump/driver/Driver.cpp @@ -49,7 +49,11 @@ int entry(int argc, char **argv) std::cout << "Dump: " << tflite_path << std::endl << std::endl; - std::cout << tflmodel << std::endl; + tfldump::ModelEx modelex; + modelex.model = tflmodel; + modelex.rawdata = &modelData; + + std::cout << modelex << std::endl; return 0; } diff --git a/compiler/tfldump/include/tfldump/Dump.h b/compiler/tfldump/include/tfldump/Dump.h index af04bb1327d..c352967887b 100644 --- a/compiler/tfldump/include/tfldump/Dump.h +++ b/compiler/tfldump/include/tfldump/Dump.h @@ -24,9 +24,16 @@ namespace tfldump { -void dump_model(std::ostream &os, const tflite::Model *model); -} +struct ModelEx +{ + const tflite::Model *model; + const std::vector *rawdata; +}; + +void dump_model(std::ostream &os, const ModelEx &model); + +} // namespace tfldump -std::ostream &operator<<(std::ostream &os, const tflite::Model *model); +std::ostream &operator<<(std::ostream &os, const tfldump::ModelEx &model); #endif // __TFLDUMP_DUMP_H__ diff --git a/compiler/tfldump/src/Dump.cpp b/compiler/tfldump/src/Dump.cpp index 7139f9ca46c..548f5878b83 100644 --- a/compiler/tfldump/src/Dump.cpp +++ b/compiler/tfldump/src/Dump.cpp @@ -340,9 +340,9 @@ void dump_sub_graph(std::ostream &os, tflread::Reader &reader) os << std::endl; } -void dump_model(std::ostream &os, const tflite::Model *model) +void dump_model(std::ostream &os, const tflite::Model *model, const std::vector *rawdata) { - tflread::Reader reader(model); + tflread::Reader reader(model, rawdata); uint32_t num_subgraph = reader.num_subgraph(); @@ -376,13 +376,17 @@ void dump_model(std::ostream &os, const tflite::Model *model) os << std::endl; // dump buffer - os << "Buffers: B(index) (length) values, if any" << std::endl; + os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl; for (uint32_t i = 0; i < buffers->size(); ++i) { + bool ext_offset = false; const uint8_t *buff_data; - size_t size = reader.buffer_info(i, &buff_data); + size_t size = reader.buffer_info(i, &buff_data, ext_offset); - os << "B(" << i << ") (" << size << ") "; + os << "B(" << i << ") (" << size; + if (ext_offset) + os << " *"; + os << ") "; if (buff_data != nullptr) { dump_buffer(os, buff_data, size, 16); @@ -450,8 +454,8 @@ void dump_model(std::ostream &os, const tflite::Model *model) } // namespace tfldump -std::ostream &operator<<(std::ostream &os, const tflite::Model *model) +std::ostream &operator<<(std::ostream &os, const tfldump::ModelEx &modelex) { - tfldump::dump_model(os, model); + tfldump::dump_model(os, modelex.model, modelex.rawdata); return os; } diff --git a/compiler/tfldump/src/Read.cpp b/compiler/tfldump/src/Read.cpp index f55d86dda5b..fe921c65d16 100644 --- a/compiler/tfldump/src/Read.cpp +++ b/compiler/tfldump/src/Read.cpp @@ -18,6 +18,7 @@ #include +#include #include #include @@ -39,6 +40,23 @@ Reader::Reader(const tflite::Model *model) } } +Reader::Reader(const tflite::Model *model, const std::vector *rawdata) +{ + _rawdata = rawdata; + + _version = model->version(); + _subgraphs = model->subgraphs(); + _buffers = model->buffers(); + _metadata = model->metadata(); + _signaturedefs = model->signature_defs(); + + auto opcodes = model->operator_codes(); + for (const ::tflite::OperatorCode *opcode : *opcodes) + { + _op_codes.push_back(opcode); + } +} + size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) { *buff_data = nullptr; @@ -61,6 +79,47 @@ size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) return 0; } +size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset) +{ + *buff_data = nullptr; + ext_offset = false; + + if (buf_idx == 0) + return 0; + + if (auto *buffer = (*_buffers)[buf_idx]) + { + auto buffer_offset = buffer->offset(); + if (buffer->offset() > 1) + { + assert(_rawdata); // make debug break for invalid case + if (_rawdata == nullptr) + return 0; + + ext_offset = true; + *buff_data = reinterpret_cast(&_rawdata->at(buffer_offset)); + return buffer->size(); + } + else if (auto *array = buffer->data()) + { + if (size_t size = array->size()) + { + *buff_data = reinterpret_cast(array->data()); + return size; + } + } + else + { + if (buffer->offset() == 1 && buffer->size() == 1) + { + std::cerr << "Buffer " << buf_idx << " has invalid offset/size." << std::endl; + } + } + } + + return 0; +} + tflite::BuiltinOperator Reader::builtin_code(const tflite::Operator *op) const { uint32_t index = op->opcode_index(); diff --git a/compiler/tfldump/src/Read.h b/compiler/tfldump/src/Read.h index fb4d330e70d..974f60923ce 100644 --- a/compiler/tfldump/src/Read.h +++ b/compiler/tfldump/src/Read.h @@ -51,6 +51,7 @@ class Reader public: Reader(const tflite::Model *model); + Reader(const tflite::Model *model, const std::vector *rawdata); Reader() = delete; @@ -69,6 +70,7 @@ class Reader uint32_t num_subgraph() const { return _subgraphs->size(); } size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data); + size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset); tflite::BuiltinOperator builtin_code(const tflite::Operator *op) const; std::string opcode_name(const tflite::Operator *op) const; @@ -80,6 +82,8 @@ class Reader private: uint32_t _version; + const std::vector *_rawdata{nullptr}; + const TFliteSubGraphs_t *_subgraphs{nullptr}; const TFliteBuffers_t *_buffers{nullptr}; const TFliteTensors_t *_tensors{nullptr}; diff --git a/compiler/tflite2circle/driver/Driver.cpp b/compiler/tflite2circle/driver/Driver.cpp index 6afe1b0f272..8ac630130a0 100644 --- a/compiler/tflite2circle/driver/Driver.cpp +++ b/compiler/tflite2circle/driver/Driver.cpp @@ -67,7 +67,8 @@ int entry(int argc, char **argv) auto flatbuffer_builder = std::make_unique(1024); // convert tflite to circle - tflite2circle::CircleModel circle_model{flatbuffer_builder}; + const std::vector &raw_data = tfl_model.raw_data(); + tflite2circle::CircleModel circle_model{flatbuffer_builder, raw_data}; circle_model.load_offsets(tfl_model.get_model()); circle_model.model_build(); diff --git a/compiler/tflite2circle/include/CircleModel.h b/compiler/tflite2circle/include/CircleModel.h index 189cfaff23f..719848c003c 100644 --- a/compiler/tflite2circle/include/CircleModel.h +++ b/compiler/tflite2circle/include/CircleModel.h @@ -80,6 +80,8 @@ template class Offset CIRFlatBufVecOffset _circle_flatbuffer_vec_offset; // TODO revise this when Circle supports SignatureDef const SignatureDefs *_tfl_signature_def_offsets = nullptr; + // for extended buffer for size > 2G + const std::vector *_file_raw = nullptr; }; class CircleModel @@ -89,7 +91,7 @@ class CircleModel public: CircleModel(void) = delete; - CircleModel(FlatBufBuilder &fb); + CircleModel(FlatBufBuilder &fb, const std::vector &fr); public: void load_offsets(const tflite::Model *tfl_model); @@ -101,6 +103,7 @@ class CircleModel uint32_t _version; Description _description; FlatBufBuilder &_fb; + const std::vector &_file_raw; std::unique_ptr> _operator_codes_offset; std::unique_ptr> _subGraphs_offset; std::unique_ptr> _buffers_offset; diff --git a/compiler/tflite2circle/include/TFLModel.h b/compiler/tflite2circle/include/TFLModel.h index 507667bb903..111a5b9fefc 100644 --- a/compiler/tflite2circle/include/TFLModel.h +++ b/compiler/tflite2circle/include/TFLModel.h @@ -38,6 +38,8 @@ class TFLModel public: const tflite::Model *get_model(void); + // NOTE TFLModel lifetime should be longer than users + const std::vector &raw_data(void) const { return _data; } public: bool verify_data(void); diff --git a/compiler/tflite2circle/src/CircleModel.cpp b/compiler/tflite2circle/src/CircleModel.cpp index c9465a0c615..ca2778ec354 100644 --- a/compiler/tflite2circle/src/CircleModel.cpp +++ b/compiler/tflite2circle/src/CircleModel.cpp @@ -43,9 +43,10 @@ template <> void Offset::build(const TFLFlatBufVec *tflite_flatbuffe for (auto it : *tflite_flatbuffer_vec) { flatbuffers::Offset> buffer_data; - if (it->data()) + const auto *tflbuff_data = it->data(); + if (tflbuff_data) { - std::vector data_vec{it->data()->begin(), it->data()->end()}; + std::vector data_vec{tflbuff_data->begin(), tflbuff_data->end()}; buffer_data = _fb->CreateVector(data_vec); } circle::BufferBuilder circle_buffer_builder{*_fb}; @@ -376,8 +377,8 @@ template <> void Offset::build(const TFLFlatBufVec *tflite_fla _circle_flatbuffer_vec_offset = _fb->CreateVector(operator_code_vec); } -CircleModel::CircleModel(FlatBufBuilder &fb) - : _version{0}, _description{fb->CreateString("ONE-tflite2circle")}, _fb{fb} +CircleModel::CircleModel(FlatBufBuilder &fb, const std::vector &fr) + : _version{0}, _description{fb->CreateString("ONE-tflite2circle")}, _fb{fb}, _file_raw{fr} { // NOTHING TODO } diff --git a/compute/cker/include/cker/operation/DepthwiseConv.h b/compute/cker/include/cker/operation/DepthwiseConv.h index c926ec4f12d..5be36557ee8 100644 --- a/compute/cker/include/cker/operation/DepthwiseConv.h +++ b/compute/cker/include/cker/operation/DepthwiseConv.h @@ -28,6 +28,8 @@ #include "cker/operation/reference/integer_ops/DepthwiseConvUInt8.h" #include "cker/operation/reference/integer_ops/DepthwiseConvHybrid.h" #include "cker/CpuBackendThreadpool.h" +#include "cker/eigen/depthwise_conv_op.h" +#include "cker/eigen/bias_op.h" namespace nnfw { @@ -180,6 +182,46 @@ inline void DepthwiseConv(const DepthwiseConvParams ¶ms, const Shape &input_ cpu_backend_threadpool::Execute(tasks.size(), tasks.data(), ruy_context); } +void DepthwiseConvOp(const DepthwiseConvParams ¶ms, const Shape &input_shape, + const float *input_data, const Shape &filter_shape, const float *filter_data, + const Shape &bias_shape, const float *bias_data, float *padded_filter_data, + bool pad_filter, float *filter_buffers_data, const Shape &output_shape, + float *output_data) +{ + if (params.stride_height != params.stride_width) + throw std::runtime_error("Not support different length strides"); + + if (params.dilation_height_factor != 1 || params.dilation_width_factor != 1) + throw std::runtime_error{"Not support dilation other than 1."}; + + const int batch = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = output_shape.Dims(3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride = params.stride_height; + const int depth_multiplier = params.depth_multiplier; + const int pad_height = params.padding_values.height; + const int pad_width = params.padding_values.width; + const float activation_min = params.float_activation_min; + const float activation_max = params.float_activation_max; + + depthwise_conv_op::LaunchDepthwiseConvOp()( + batch, input_height, input_width, input_depth, filter_height, filter_width, depth_multiplier, + stride, pad_height, pad_width, output_height, output_width, output_depth, input_data, + filter_data, padded_filter_data, pad_filter, filter_buffers_data, output_data); + + if (bias_data != nullptr) + { + bias_op::biasHelper(bias_shape, bias_data, output_shape, output_data, activation_min, + activation_max); + } +} + } // namespace cker } // namespace nnfw diff --git a/compute/cker/src/DepthwiseConv.test.cc b/compute/cker/src/DepthwiseConv.test.cc new file mode 100644 index 00000000000..ecb7c97db97 --- /dev/null +++ b/compute/cker/src/DepthwiseConv.test.cc @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +namespace +{ + +template class DepthwiseConvVerifier +{ +public: + DepthwiseConvVerifier() = default; + + void prepare(const nnfw::cker::Shape &output_shape, const nnfw::cker::Shape &filter_shape) + { + const int k_packet_size = nnfw::cker::eigen_support::kPacketSize(); + const int batch = output_shape.Dims(0); + const int out_depth = output_shape.Dims(3); + const int filter_rows = filter_shape.Dims(1); + const int filter_cols = filter_shape.Dims(2); + const int filter_spatial_size = filter_rows * filter_cols; + const int padded_filter_inner_dim_size = + ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; + + _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; + { + nnfw::cker::Shape padded_filter_shape( + {batch, filter_spatial_size, padded_filter_inner_dim_size}); + _padded_filter.resize(padded_filter_shape.FlatSize()); + } + + { + // NOTE The Eigen library uses both main thread as well as a thread pool. + // Therefore, it needs to add an additional memory buffer for main thread. + const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; + + nnfw::cker::Shape filter_buffer_shape( + {thread_count, filter_spatial_size, padded_filter_inner_dim_size}); + _filter_buffers.resize(filter_buffer_shape.FlatSize()); + } + } + + void run(const nnfw::cker::DepthwiseConvParams ¶ms, const nnfw::cker::Shape &input_shape, + const T *input_data, const nnfw::cker::Shape &filter_shape, const T *filter_data, + const nnfw::cker::Shape &bias_shape, const T *bias_data, + const nnfw::cker::Shape &output_shape, const T *expected) + { + std::vector output(output_shape.FlatSize()); + nnfw::cker::DepthwiseConvOp(params, input_shape, input_data, filter_shape, filter_data, + bias_shape, bias_data, _padded_filter.data(), _use_padded_filter, + _filter_buffers.data(), output_shape, output.data()); + + for (size_t i = 0; i < output.size(); ++i) + EXPECT_NEAR(output[i], expected[i], 1e-3f); + } + + void checkException(const nnfw::cker::DepthwiseConvParams ¶ms, + const nnfw::cker::Shape &input_shape, const T *input_data, + const nnfw::cker::Shape &filter_shape, const T *filter_data, + const nnfw::cker::Shape &bias_shape, const T *bias_data, + const nnfw::cker::Shape &output_shape, const T *expected) + { + std::vector output(output_shape.FlatSize()); + EXPECT_ANY_THROW( + nnfw::cker::DepthwiseConvOp(params, input_shape, input_data, filter_shape, filter_data, + bias_shape, bias_data, _padded_filter.data(), _use_padded_filter, + _filter_buffers.data(), output_shape, output.data())); + } + +private: + bool _use_padded_filter; + std::vector _padded_filter; + std::vector _filter_buffers; +}; + +} // namespace + +TEST(CKer_Operation, DepthwiseConv) +{ + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kValid; + params.padding_values.width = 0; + params.padding_values.height = 0; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 3, 2, 2}; // n, h, w, c + std::vector input = {1.0, 2.0, 7.0, 8.0, 3.0, 4.0, 9.0, 10.0, 5.0, 6.0, 11.0, 12.0}; + nnfw::cker::Shape filter_shape{1, 2, 2, 2}; // 1, h, w, c + std::vector filter = {1.0, 2.0, 3.0, 4.0, -9.0, 10.0, -11.0, 12.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.0, 0.0}; + nnfw::cker::Shape output_shape{1, 2, 1, 2}; // n, h, w, c + std::vector expected = {-104., 196.0, -136.0, 252.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Pad + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.0, 0.0}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.0, 28.0, 28.0, 44.0, 8.0, 16.0, 12.0, 24.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Bias + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.5, -0.5}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.5, 27.5, 28.5, 43.5, 8.5, 15.5, 12.5, 23.5}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Depth Multiplier + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 2; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 4}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0}; + nnfw::cker::Shape bias_shape{4}; + std::vector bias = {0.5, -0.5, 0.3, -0.3}; + nnfw::cker::Shape output_shape{1, 2, 2, 4}; // n, h, w, c + std::vector expected = {-11.5, -8.5, -9.7, -4.3, -9.5, -2.5, -21.7, -12.3, + 16.5, 19.5, -22.7, -17.3, 24.5, 31.5, -28.7, -19.3}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // ReLU6 + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = 0.0; + params.float_activation_max = 6.0; + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.5, -0.5}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // No bias + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.0, 28.0, 28.0, 44.0, 8.0, 16.0, 12.0, 24.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + nullptr, output_shape, expected.data()); + } +} + +TEST(CKer_Operation, neg_DepthwiseConv) +{ + // Not supported Dilation + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 2; + params.dilation_height_factor = 2; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 6, 6, 1}; // n, h, w, c + std::vector input = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + nnfw::cker::Shape filter_shape{1, 2, 2, 1}; // 1, h, w, c + std::vector filter = {1.0, 2.0, 3.0, 4.0}; + nnfw::cker::Shape bias_shape{1}; + std::vector bias = {0.0}; + nnfw::cker::Shape output_shape{1, 3, 3, 1}; // n, h, w, c + std::vector expected = {4.0, 0.0, 3.0, 0.0, 0.0, 0.0, 2.0, 0.0, 1.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.checkException(params, input_shape, input.data(), filter_shape, filter.data(), + bias_shape, bias.data(), output_shape, expected.data()); + } +} diff --git a/docs/howto/how-to-use-nnfw-python-api.md b/docs/howto/how-to-use-nnfw-python-api.md index 5d5b839cc63..5a18b79aeb2 100644 --- a/docs/howto/how-to-use-nnfw-python-api.md +++ b/docs/howto/how-to-use-nnfw-python-api.md @@ -17,13 +17,11 @@ Please see [nnfw python api](https://github.com/SAMSUNG/ONE/tree/master/infra/nn 1. Initialize nnfw_session ```python +import onert + # Create session and load nnpackage -# operations is optional to assign a specific backends to each operation. # The default value of backends is "cpu". -if operations: - session = nnfw_session(nnpackage_path, backends, operations) -else: - session = nnfw_session(nnpackage_path, backends) +session = onert.infer.session(nnpackage_path, backends) ``` 2. Prepare Input diff --git a/docs/runtime/training.md b/docs/runtime/training.md new file mode 100644 index 00000000000..31ab2bdd410 --- /dev/null +++ b/docs/runtime/training.md @@ -0,0 +1,59 @@ +# Training + +## Overview + +ONERT supports model training. In particular, it supports training not only in the Host environment but also in the On-device environment and provides features for on-device training. Training is an important part of developing and improving models. While general learning in the Host environment involves training with a large amount of data using many resources, in the on-device environment there is limited space to store data, and the resources that can be used are also limited. Therefore, efficient learning using less data and small resources is required for on-devcie training. ONERT provides various features to meet these requirements. + +It supports on-device training based on existing trained models and supports transfer learning to learn new data added to the trained model. It also provides supervised fine-tuning to improve the accuracy of the trained model. This allows ONERT to support efficient learning with less data. + +In order to efficiently learn models with limited resources, ONERT not only uses less memory by reusing it memory space during training but also quickly improves accuracy of trained model by performing optimized kernel for each operation. + +Trained model can be saved to be deployed using ONERT API. This allows users to redeploy it to other environments or real applications to perform inference and retraining. + +## Training in ONERT + +### Training options + +ONERT supports the following options: + +- Loss function + - w/ loss reduction type +- Optimizer + - w/ learning rate +- Batch size +- Num of trainable operations + +### Training process + +Prerequisites: + +- Prepare a circle model to be trained. +- Prepare your dataset and preprocess it if necessary. + +Training process in ONERT consists of the following steps: + +1. Create a session. +2. Load a circle model. + - (optional) Load the checkpoint. (for fine-tuning) +3. Set training information. +4. Prepare training a model. +5. Set input and expected data. +6. Run training. + - (optional) Get loss and accuracy. + - (optional) Save the checkpoint. +7. Validate the model. +8. Export the trained model for inference. + +### Training tools + +- [onert_train](tests/tools/onert_train): A tool to train neural networks with ONERT. +- [generate_datafile](tools/generate_datafile): A tool to generate data files for ONERT training. +- [circle_plus_gen](tools/circle_plus_gen): A tool to generate Circle+ model from circle model. + +## Example + +### Training well-known models using ONERT + +### Advanced Topics + +- [Transfer Learning](docs/runtime/transfer_learning.md) diff --git a/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake b/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake index d98882a32cc..cc77b844d1d 100644 --- a/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake +++ b/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake @@ -132,4 +132,53 @@ if(FlatBuffers_FOUND) target_include_directories(${TGT} PUBLIC "${ARG_INCLUDE_DIR}") target_link_libraries(${TGT} PUBLIC flatbuffers-23.5.26) endfunction(FlatBuffers_Target) + + function(FlatBuffersMuteable_Target TGT) + set(oneValueArgs OUTPUT_DIR SCHEMA_DIR INCLUDE_DIR) + set(multiValueArgs SCHEMA_FILES) + cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Use OUTPUT_DIR as INCLUDE_DIR if INCLUDE_DIR is not specified + if(NOT ARG_INCLUDE_DIR) + set(ARG_INCLUDE_DIR ${ARG_OUTPUT_DIR}) + endif(NOT ARG_INCLUDE_DIR) + + get_filename_component(abs_output_dir ${ARG_OUTPUT_DIR} ABSOLUTE) + get_filename_component(abs_include_dir ${ARG_INCLUDE_DIR} ABSOLUTE) + get_filename_component(abs_schema_dir ${ARG_SCHEMA_DIR} ABSOLUTE) + + # Let's reset list variables before using them + # NOTE THIS DOES NOT AFFECT parent scope + unset(SCHEMA_FILES) + unset(OUTPUT_FILES) + + foreach(schema ${ARG_SCHEMA_FILES}) + get_filename_component(schema_fn "${schema}" NAME) + get_filename_component(dir "${schema}" DIRECTORY) + + get_filename_component(schema_fn_we "${schema_fn}" NAME_WE) + + list(APPEND SCHEMA_FILES "${abs_schema_dir}/${schema}") + list(APPEND OUTPUT_FILES "${abs_output_dir}/${schema_fn_we}_generated.h") + endforeach() + + # Generate headers + add_custom_command(OUTPUT ${OUTPUT_FILES} + COMMAND ${CMAKE_COMMAND} -E make_directory "${abs_output_dir}" + COMMAND "${FLATC_PATH}" -c --no-includes + --no-union-value-namespacing + --gen-object-api + --gen-mutable + -o "${abs_output_dir}" + ${SCHEMA_FILES} + DEPENDS ${SCHEMA_FILES} + COMMENT "Generate '${TGT}' headers") + + # NOTE This header-only library is deliberately declared as STATIC library + # to avoid possible scope issues related with generated files + add_library(${TGT} STATIC ${OUTPUT_FILES}) + set_target_properties(${TGT} PROPERTIES LINKER_LANGUAGE CXX) + target_include_directories(${TGT} PUBLIC "${ARG_INCLUDE_DIR}") + target_link_libraries(${TGT} PUBLIC flatbuffers-23.5.26) + endfunction(FlatBuffersMuteable_Target) endif(FlatBuffers_FOUND) diff --git a/infra/debian/runtime/control b/infra/debian/runtime/control index 86b169ebff5..baa0d029816 100644 --- a/infra/debian/runtime/control +++ b/infra/debian/runtime/control @@ -6,20 +6,40 @@ Build-Depends: cmake, debhelper (>=9) Standards-Version: 3.9.8 Homepage: https://github.com/Samsung/ONE -Package: nnfw +Package: onert +Replaces: nnfw (<< 1.29.0) +Breaks: nnfw (<< 1.29.0) Architecture: amd64 Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Description: one-runtime package -Package: nnfw-dev +Package: nnfw +Architecture: all +Priority: optional +Section: oldlibs +Depends: onert, ${shlibs:Depends}, ${misc:Depends} +Description: one-runtime transitional package + This is a transitional package. It can safely be removed. + +Package: onert-dev +Replaces: nnfw-dev (<< 1.29.0) +Breaks: nnfw-dev (<< 1.29.0) Architecture: amd64 Multi-Arch: same -Depends: nnfw, ${shlibs:Depends}, ${misc:Depends} +Depends: onert, ${shlibs:Depends}, ${misc:Depends} Description: one-runtime development package -Package: nnfw-plugin-dev +Package: nnfw-dev +Architecture: all +Priority: optional +Section: oldlibs +Depends: onert-dev, ${shlibs:Depends}, ${misc:Depends} +Description: one-runtime development transitional package + This is a transitional package. It can safely be removed. + +Package: onert-plugin-dev Architecture: amd64 Multi-Arch: same -Depends: nnfw, nnfw-dev, ${shlibs:Depends}, ${misc:Depends} +Depends: onert, onert-dev, ${shlibs:Depends}, ${misc:Depends} Description: one-runtime development package diff --git a/infra/debian/runtime/nnfw-dev.install b/infra/debian/runtime/onert-dev.install similarity index 61% rename from infra/debian/runtime/nnfw-dev.install rename to infra/debian/runtime/onert-dev.install index f246e7c24ea..5aab8f5800a 100644 --- a/infra/debian/runtime/nnfw-dev.install +++ b/infra/debian/runtime/onert-dev.install @@ -1,4 +1,4 @@ # {FILES_TO_INSTALL} {DEST_DIR} # include usr/include/nnfw usr/include/ -usr/lib/pkgconfig/*.pc usr/lib/pkgconfig/ +usr/lib/pkgconfig/onert.pc usr/lib/pkgconfig/ diff --git a/infra/debian/runtime/nnfw-plugin-dev.install b/infra/debian/runtime/onert-plugin-dev.install similarity index 54% rename from infra/debian/runtime/nnfw-plugin-dev.install rename to infra/debian/runtime/onert-plugin-dev.install index 1f19e54d8de..7db4391bf9a 100644 --- a/infra/debian/runtime/nnfw-plugin-dev.install +++ b/infra/debian/runtime/onert-plugin-dev.install @@ -1,3 +1,3 @@ # {FILES_TO_INSTALL} {DEST_DIR} usr/include/onert usr/include/ -usr/lib/pkgconfig/nnfw-plugin.pc usr/lib/pkgconfig/ +usr/lib/pkgconfig/onert-plugin.pc usr/lib/pkgconfig/ diff --git a/infra/debian/runtime/nnfw.install b/infra/debian/runtime/onert.install similarity index 100% rename from infra/debian/runtime/nnfw.install rename to infra/debian/runtime/onert.install diff --git a/infra/debian/runtime/rules b/infra/debian/runtime/rules index 47a6d51dbe3..ffe3d04d42a 100755 --- a/infra/debian/runtime/rules +++ b/infra/debian/runtime/rules @@ -24,13 +24,14 @@ override_dh_auto_install: ./nnfw install --prefix $(NNFW_INSTALL_PREFIX) --strip override_dh_install: install -d $(NNFW_INSTALL_PREFIX)/lib/pkgconfig - sed -i 's:@libdir@:\/usr\/lib:g' ./packaging/nnfw.pc.in - sed -i 's:@includedir@:\/usr\/include:g' ./packaging/nnfw.pc.in - sed -i 's:@version@:${DEBVER}:g' ./packaging/nnfw.pc.in - sed -i 's:@libdir@:\/usr\/lib:g' ./packaging/nnfw-plugin.pc.in - sed -i 's:@includedir@:\/usr\/include:g' ./packaging/nnfw-plugin.pc.in - sed -i 's:@version@:${DEBVER}:g' ./packaging/nnfw-plugin.pc.in - - install -m 0644 packaging/nnfw.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/nnfw.pc - install -m 0644 packaging/nnfw-plugin.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/nnfw-plugin.pc + install -m 0644 packaging/nnfw.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + install -m 0644 packaging/nnfw-plugin.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@libdir@:\/usr\/lib:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@includedir@:\/usr\/include:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@version@:${DEBVER}:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:Name\: nnfw:Name\: onert:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@libdir@:\/usr\/lib:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@includedir@:\/usr\/include:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@version@:${DEBVER}:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:Name\: nnfw:Name\: onert:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc dh_install diff --git a/infra/nnfw/python/.gitignore b/infra/nnfw/python/.gitignore index 15d72def6a6..52796b1b1d1 100644 --- a/infra/nnfw/python/.gitignore +++ b/infra/nnfw/python/.gitignore @@ -1,4 +1,4 @@ build/ dist/ -nnfwapi/ -nnfwapi.egg-info/ +onert/ +onert.egg-info/ diff --git a/infra/nnfw/python/README.md b/infra/nnfw/python/README.md index 2a5942e5eb3..c34acd9e4b7 100644 --- a/infra/nnfw/python/README.md +++ b/infra/nnfw/python/README.md @@ -1,12 +1,12 @@ -# nnfwapi package +# onert package -`nnfwapi` is a package to run `nnpackage` with the nnfw python API. +`onert` is a package to run `nnpackage` with the nnfw onert's python API. -This package includes the nnfw python API module resulting from runtime build. +This package includes the nnfw-onert python API module resulting from runtime build. It is provided separate package for each architecture(x86_64, armv7l, aarch64). -It uses `nnfwapi/libnnfw_api_pybind.py` interface. +It uses `onert/infer.py` interface. ## Packaging Execute this command, then the tasks such as copying modules, and packaging. @@ -39,17 +39,25 @@ $ twine upload --repository-url https://test.pypi.org/legacy/ dist/* You can install the package as follows: ``` -$ pip install -i https://test.pypi.org/simple/ nnfwapi +$ pip install -i https://test.pypi.org/simple/ nnfw-onert ``` By specifying the version, you can use a specific version of the package. (recommended) ``` -$ pip install -i https://test.pypi.org/simple/ nnfwapi==0.1.1 +$ pip install -i https://test.pypi.org/simple/ nnfw-onert==0.1.1 ``` This definition has to be set at the top of the script using nnfw python API. ``` -from nnfwapi.libnnfw_api_pybind import * +import onert ``` + +Or you can import the onert module directly. + +``` +from onert.infer import * +``` + +This can be use onert session directly. diff --git a/infra/nnfw/python/setup.py b/infra/nnfw/python/setup.py index 8217c1219fb..e3c5baf12d9 100644 --- a/infra/nnfw/python/setup.py +++ b/infra/nnfw/python/setup.py @@ -4,7 +4,8 @@ import sys architecture_directory = ['x86_64', 'armv7l', 'aarch64'] -package_directory = 'nnfwapi' +package_name = 'onert' +package_directory = 'onert' packaging_directory = ['build', package_directory + '.egg-info'] THIS_FILE_DIR = os.path.dirname(os.path.abspath(__file__)) DEFAULT_PRODUCT_DIR = "../../../Product" @@ -66,7 +67,7 @@ shutil.rmtree(arch_path) # make architecture_directory and copy .so files to the directories - arch_path = os.path.join(package_directory, 'onert') + arch_path = os.path.join(package_directory, 'native') os.makedirs(arch_path) print(f"Created directory '{arch_path}'") @@ -81,7 +82,7 @@ def get_directories(): for so in os.listdir(so_core_dir): if so.endswith(".so"): - so_list.append('onert/' + so) + so_list.append('native/' + so) src_path = os.path.join(so_core_dir, so) tgt_path = os.path.join(arch_path, so) shutil.copy(src_path, tgt_path) @@ -94,7 +95,7 @@ def get_directories(): os.makedirs(so_backend_tgt_dir) for so in os.listdir(so_backend_dir): if so.endswith(".so"): - so_list.append('onert/nnfw/backend/' + so) + so_list.append('native/nnfw/backend/' + so) src_path = os.path.join(so_backend_dir, so) tgt_path = os.path.join(so_backend_tgt_dir, so) shutil.copy(src_path, tgt_path) @@ -107,7 +108,7 @@ def get_directories(): os.makedirs(so_odc_tgt_dir) for so in os.listdir(so_odc_dir): if so.endswith(".so"): - so_list.append('onert/nnfw/odc/' + so) + so_list.append('native/nnfw/odc/' + so) src_path = os.path.join(so_odc_dir, so) tgt_path = os.path.join(so_odc_tgt_dir, so) shutil.copy(src_path, tgt_path) @@ -121,7 +122,7 @@ def get_directories(): # copy .so files to architecture directories setup( - name=package_directory, + name=package_name, version='0.1.0', description='nnfw_api binding', long_description='It provides nnfw Python api', diff --git a/onert-micro/onert-micro/include/OMConfig.h b/onert-micro/onert-micro/include/OMConfig.h index 0ffbf024b1f..c9ded00f3a5 100644 --- a/onert-micro/onert-micro/include/OMConfig.h +++ b/onert-micro/onert-micro/include/OMConfig.h @@ -41,6 +41,7 @@ enum OMMetrics MAE_METRICS, CROSS_ENTROPY_METRICS, ACCURACY, + SPARSE_CROSS_ENTROPY_ACCURACY, }; /* @@ -52,6 +53,7 @@ enum OMLoss CROSS_ENTROPY, MSE, MAE, + SPARSE_CROSS_ENTROPY, }; /* diff --git a/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h b/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h index 5aea894d47f..fc08257f156 100644 --- a/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h +++ b/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h @@ -110,8 +110,8 @@ template void evalComparisonGeneric(OMRuntimeKernel *runtime_kernel } } -template -void evalQuantizedComparisonGeneric(OMRuntimeKernel *runtime_kernel, bool F(T, T)) +template +void evalQuantizedComparisonGeneric(OMRuntimeKernel *runtime_kernel, bool F(AccType, AccType)) { const circle::Tensor *input1 = nullptr; const circle::Tensor *input2 = nullptr; diff --git a/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h b/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h new file mode 100644 index 00000000000..67efc055d71 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2017 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_EXECUTE_PAL_ARG_MAX_H +#define ONERT_MICRO_EXECUTE_PAL_ARG_MAX_H + +#include "PALArgMinMaxCommon.h" +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +template +OMStatus ArgMax(const core::OMRuntimeShape &input1_shape, const T1 *input1_data, + const T3 *input2_data, const core::OMRuntimeShape &output_shape, T2 *output_data) +{ + return ArgMinMax(input1_shape, input1_data, input2_data, output_shape, output_data, + std::greater()); +} +} // namespace pal +} // namespace execute +} // namespace onert_micro +#endif // ONERT_MICRO_EXECUTE_PAL_ARG_MAX_H diff --git a/onert-micro/onert-micro/include/pal/common/PALComparisons.h b/onert-micro/onert-micro/include/pal/common/PALComparisons.h index 0f37d2f19c8..0770196ff32 100644 --- a/onert-micro/onert-micro/include/pal/common/PALComparisons.h +++ b/onert-micro/onert-micro/include/pal/common/PALComparisons.h @@ -71,11 +71,11 @@ inline void ComparisonNoScaling(const int64_t flat_size, const T *input1_data, c } } -template +template inline void BroadcastComparison4DSlowWithScaling( const core::ComparisonParams &op_params, const core::OMRuntimeShape &unextended_input1_shape, const T *input1_data, const core::OMRuntimeShape &unextended_input2_shape, const T *input2_data, - const core::OMRuntimeShape &unextended_output_shape, bool *output_data, bool F(T, T)) + const core::OMRuntimeShape &unextended_output_shape, bool *output_data, bool F(AccType, AccType)) { const BroadcastComparison4DSlowCommon dims = BroadcastComparison4DSlowPreprocess( unextended_input1_shape, unextended_input2_shape, unextended_output_shape); @@ -118,10 +118,10 @@ inline void BroadcastComparison4DSlowWithScaling( } } -template +template inline void ComparisonWithScaling(const core::ComparisonParams &op_params, const int64_t flat_size, const T *input1_data, const T *input2_data, bool *output_data, - bool F(T, T)) + bool F(AccType, AccType)) { int left_shift = op_params.left_shift; int32_t input1_offset = op_params.input1_offset; diff --git a/onert-micro/onert-micro/include/pal/common/PALElu.h b/onert-micro/onert-micro/include/pal/common/PALElu.h index fdb46098b15..a5687562eed 100644 --- a/onert-micro/onert-micro/include/pal/common/PALElu.h +++ b/onert-micro/onert-micro/include/pal/common/PALElu.h @@ -34,7 +34,7 @@ inline OMStatus Elu(const int flat_size, const float *input_data, float *output_ for (int i = 0; i < flat_size; i++) { float val = input_data[i]; - float result = val < 0.0f ? std::expm1(val) : val; + float result = val < 0.0f ? std::exp(val) - 1 : val; output_data[i] = result; } diff --git a/onert-micro/onert-micro/include/pal/common/PALLogistic.h b/onert-micro/onert-micro/include/pal/common/PALLogistic.h index de0f4f94fdd..298515531bc 100644 --- a/onert-micro/onert-micro/include/pal/common/PALLogistic.h +++ b/onert-micro/onert-micro/include/pal/common/PALLogistic.h @@ -96,7 +96,7 @@ OMStatus inline Logistic(const int flat_size, const int8_t *input_data, float in result = 1.f / (1.f + std::exp(-val)); } // Requantize - int8_t output = static_cast(result / output_scale + output_zero_point); + int8_t output = static_cast(std::round(result / output_scale) + output_zero_point); output_data[i] = output; } return Ok; diff --git a/onert-micro/onert-micro/include/pal/common/PALQuantize.h b/onert-micro/onert-micro/include/pal/common/PALQuantize.h new file mode 100644 index 00000000000..8f6c9e54966 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/common/PALQuantize.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_EXECUTE_PAL_QUANTIZE_COMMON_H +#define ONERT_MICRO_EXECUTE_PAL_QUANTIZE_COMMON_H + +#include "core/OMRuntimeShape.h" +#include "OMStatus.h" +#include "core/OMKernelData.h" +#include "PALUtils.h" + +#include + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +template +OMStatus Quantize(const core::QuantizationParams op_params, const uint32_t flat_size, + const InputT *input_data, OutputT *output_data) +{ + const int32_t zero_point = op_params.zero_point; + const double scale = op_params.scale; + static constexpr int32_t min_val = std::numeric_limits::min(); + static constexpr int32_t max_val = std::numeric_limits::max(); + + for (int i = 0; i < flat_size; i++) + { + const InputT val = input_data[i]; + int32_t unclamped = + static_cast(std::round(val / static_cast(scale))) + zero_point; + int32_t clamped = std::min(std::max(unclamped, min_val), max_val); + output_data[i] = clamped; + } + + return Ok; +} +} // namespace pal +} // namespace execute +} // namespace onert_micro + +#endif // ONERT_MICRO_EXECUTE_PAL_DEQUANTIZE_COMMON_H diff --git a/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h new file mode 100644 index 00000000000..f396a63635f --- /dev/null +++ b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_EXECUTE_PAL_SVDF_COMMON_H +#define ONERT_MICRO_EXECUTE_PAL_SVDF_COMMON_H + +#include "PALUtils.h" + +#include "core/OMKernelData.h" + +#include + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +namespace +{ +// Returns the floating point value for a fused activation: +inline float activationValFloat(const circle::ActivationFunctionType act, float a) +{ + switch (act) + { + case circle::ActivationFunctionType_NONE: + return a; + case circle::ActivationFunctionType_RELU: + return std::max(0.0f, a); + case circle::ActivationFunctionType_RELU_N1_TO_1: + return std::max(-1.0f, std::min(a, 1.0f)); + case circle::ActivationFunctionType_RELU6: + return std::max(0.0f, std::min(a, 6.0f)); + case circle::ActivationFunctionType_TANH: + return std::tanh(a); + case circle::ActivationFunctionType_SIGN_BIT: + return (a < 0) ? true : false; + default: + assert(false && "Not supported"); + } + return 0.0f; // To indicate an unsupported activation (i.e. when a new fused + // activation is added to the enum and not handled here). +} + +static inline void +applyTimeWeightsBiasAndActivation(int batch_size, int memory_size, int num_filters, int num_units, + int rank, const float *const weights_time_ptr, + const float *const bias_ptr, + circle::ActivationFunctionType activation, float *const state_ptr, + float *const scratch_ptr, float *const output_ptr) +{ + // Compute matmul(activation_state, weights_time). + for (int b = 0; b < batch_size; ++b) + { + // Perform batched vector dot product: + float *scratch_ptr_batch = scratch_ptr + b * num_filters; + const float *vector1_ptr = weights_time_ptr; + const float *vector2_ptr = state_ptr + b * memory_size * num_filters; + for (int i = 0; i < num_filters; ++i) + { + *scratch_ptr_batch = 0.f; + for (int j = 0; j < memory_size; ++j) + { + *scratch_ptr_batch += *vector1_ptr++ * *vector2_ptr++; + } + scratch_ptr_batch++; + } + } + + // Initialize output with bias if provided. + if (bias_ptr) + { + // VectorBatchVectorAssign + for (int i = 0; i < batch_size; ++i) + { + float *output_data = output_ptr + i * num_units; + const float *bias_data = bias_ptr; + for (int j = 0; j < num_units; ++j) + { + *output_data++ = *bias_data++; + } + } + } + else + { + float *output_data = output_ptr; + for (int i = 0; i < batch_size * num_units; ++i) + { + *output_data++ = 0.0f; + } + } + + // Reduction sum. + for (int b = 0; b < batch_size; ++b) + { + float *output_ptr_batch = output_ptr + b * num_units; + float *scratch_ptr_batch = scratch_ptr + b * num_filters; + + // Reduction sum vector + for (int i = 0; i < num_units; ++i) + { + for (int j = 0; j < rank; j++) + { + output_ptr_batch[i] += *scratch_ptr_batch++; + } + } + } + + // Apply activation. + for (int b = 0; b < batch_size; ++b) + { + float *output_ptr_batch = output_ptr + b * num_units; + for (int i = 0; i < num_units; ++i) + { + *output_ptr_batch = activationValFloat(activation, *output_ptr_batch); + ++output_ptr_batch; + } + } +} + +} // namespace + +OMStatus SVDF(const float *input_data, const float *weights_feature_data, + const float *weights_time_data, const float *bias_data, float *state_data, + float *scratch_data, float *output_data, const int rank, const int input_size, + const int batch_size, const int num_filters, const int num_units, + const int memory_size, const circle::ActivationFunctionType activation) +{ + // Left shift the activation_state. + { + float *new_state_start = state_data; + const float *old_state_start = state_data + 1; + const float *old_state_end = state_data + batch_size * num_filters * memory_size; + while (old_state_start != old_state_end) + { + *new_state_start++ = *old_state_start++; + } + } + + // Note: no need to clear the latest activation, matmul is not accumulative. + + // Compute conv1d(inputs, weights_feature). + // The activation_state's rightmost column is used to save current cycle + // activation. This is achieved by starting at state_ptr[memory_size - 1] and + // having the stride equal to memory_size. + + // Perform batched matrix vector multiply operation: + { + const float *matrix = weights_feature_data; + const float *vector = input_data; + float *result = &state_data[memory_size - 1]; + float *result_in_batch = result; + for (int i = 0; i < batch_size; ++i) + { + const float *matrix_ptr = matrix; + for (int j = 0; j < num_filters; ++j) + { + float dot_prod = 0.0f; + const float *vector_in_batch = vector + i * input_size; + for (int k = 0; k < input_size; ++k) + { + dot_prod += *matrix_ptr++ * *vector_in_batch++; + } + *result_in_batch = dot_prod; + result_in_batch += memory_size; + } + } + } + + applyTimeWeightsBiasAndActivation(batch_size, memory_size, num_filters, num_units, rank, + weights_time_data, bias_data, activation, state_data, + scratch_data, output_data); + return Ok; +} + +} // namespace pal +} // namespace execute +} // namespace onert_micro + +#endif // ONERT_MICRO_EXECUTE_PAL_SVDF_COMMON_H diff --git a/onert-micro/onert-micro/include/pal/common/PALSubCommon.h b/onert-micro/onert-micro/include/pal/common/PALSubCommon.h index 1df3370c020..62964a51f56 100644 --- a/onert-micro/onert-micro/include/pal/common/PALSubCommon.h +++ b/onert-micro/onert-micro/include/pal/common/PALSubCommon.h @@ -25,6 +25,26 @@ namespace execute { namespace pal { + +int8_t SubFunc(int8_t x, int8_t y, const core::ArithmeticQuantParams ¶ms) +{ + const int32_t input1_val = params.input1_offset + x; + const int32_t input2_val = params.input2_offset + y; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = multiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = multiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sum = scaled_input1_val - scaled_input2_val; + const int32_t raw_output = multiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + return static_cast(clamped_output); +} + template OMStatus Sub(const core::BinaryArithmeticBroadcastParams ¶ms, const int flat_size, const T *input1_data, const T *input2_data, T *output_data) @@ -44,6 +64,16 @@ OMStatus BroadcastSub4DSlow(const core::BinaryArithmeticBroadcastParams ¶ms, return Ok; } +OMStatus BroadcastSub4DSlow(const core::ArithmeticQuantParams ¶ms, + const core::OMRuntimeShape &input1_shape, const int8_t *input1_data, + const core::OMRuntimeShape &input2_shape, const int8_t *input2_data, + const core::OMRuntimeShape &output_shape, int8_t *output_data) +{ + BroadcastBinaryFunction6DSlow(params, input1_shape, input1_data, input2_shape, input2_data, + output_shape, output_data, SubFunc); + return Ok; +} + } // namespace pal } // namespace execute } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst index b06563c1151..2560554777a 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -30,7 +30,7 @@ REGISTER_KERNEL(FILL, Fill) REGISTER_KERNEL(FLOOR, Floor) REGISTER_KERNEL(FLOOR_DIV, FloorDiv) REGISTER_KERNEL(FLOOR_MOD, FloorMod) -#/*REGISTER_KERNEL(PACK, Pack)*/ +REGISTER_KERNEL(PACK, Pack) REGISTER_KERNEL(PAD, Pad) #/*REGISTER_KERNEL(PADV2, PadV2)*/ #/*REGISTER_KERNEL(PRELU, PRelu)*/ @@ -64,18 +64,18 @@ REGISTER_KERNEL(SUB, Sub) REGISTER_KERNEL(SPLIT, Split) REGISTER_KERNEL(SPACE_TO_BATCH_ND, SpaceToBatchND) REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) -#/*REGISTER_KERNEL(SPLIT_V, SplitV)*/ +REGISTER_KERNEL(SPLIT_V, SplitV) REGISTER_KERNEL(SQUARE, Square) REGISTER_KERNEL(SQRT, Sqrt) REGISTER_KERNEL(SPACE_TO_DEPTH, SpaceToDepth) -#/*REGISTER_KERNEL(QUANTIZE, Quantize)*/ +REGISTER_KERNEL(QUANTIZE, Quantize) REGISTER_KERNEL(TANH, Tanh) REGISTER_KERNEL(TRANSPOSE, Transpose) REGISTER_KERNEL(TRANSPOSE_CONV, TransposeConv) REGISTER_KERNEL(SOFTMAX, Softmax) #/*REGISTER_KERNEL(SUM, Sum)*/ #/*REGISTER_KERNEL(SELECT_V2, SelectV2)*/ -#/*REGISTER_KERNEL(SVDF, SVDF)*/ +REGISTER_KERNEL(SVDF, SVDF) REGISTER_KERNEL(WHILE, While) #/*REGISTER_KERNEL(UNIDIRECTIONAL_SEQUENCE_LSTM, UnidirectionalSequenceLSTM)*/ #/*REGISTER_KERNEL(RESIZE_BILINEAR, ResizeBilinear)*/ diff --git a/compiler/luci/export/src/Optimize.h b/onert-micro/onert-micro/include/pal/mcu/PALSVDF.h similarity index 67% rename from compiler/luci/export/src/Optimize.h rename to onert-micro/onert-micro/include/pal/mcu/PALSVDF.h index c3af7a04cbc..e1c707607c4 100644 --- a/compiler/luci/export/src/Optimize.h +++ b/onert-micro/onert-micro/include/pal/mcu/PALSVDF.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 The TensorFlow Authors. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +15,9 @@ * limitations under the License. */ -#ifndef __OPTIMIZE_H__ -#define __OPTIMIZE_H__ +#ifndef ONERT_MICRO_EXECUTE_PAL_SVDF_H +#define ONERT_MICRO_EXECUTE_PAL_SVDF_H -#include +#include "PALSVDFCommon.h" -namespace luci -{ - -/** - * @brief Run passes of graph transformations - * - */ -void optimize(loco::Graph *); - -} // namespace luci - -#endif // __OPTIMIZE_H__ +#endif // ONERT_MICRO_EXECUTE_PAL_SVDF_H diff --git a/onert-micro/onert-micro/include/pal/mcu/PALSub.h b/onert-micro/onert-micro/include/pal/mcu/PALSub.h index a3bd4b7368a..60c5fb6eac8 100644 --- a/onert-micro/onert-micro/include/pal/mcu/PALSub.h +++ b/onert-micro/onert-micro/include/pal/mcu/PALSub.h @@ -19,5 +19,24 @@ #define ONERT_MICRO_EXECUTE_PAL_SUB_H #include "PALSubCommon.h" +#include "PALUtils.h" + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +OMStatus Sub(const core::ArithmeticQuantParams ¶ms, const uint32_t flat_size, + const int8_t *input1_data, const int8_t *input2_data, int8_t *output_data) +{ + ElementWise(flat_size, params, input1_data, input2_data, output_data, SubFunc); + return Ok; +} + +} // namespace pal +} // namespace execute +} // namespace onert_micro #endif // ONERT_MICRO_EXECUTE_PAL_MUL_H diff --git a/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h b/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h new file mode 100644 index 00000000000..d341c5fcb6e --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_CONCATENATION_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_CONCATENATION_KERNEL_S8_H + +#include "TestDataConcatenationBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace concatenation_s8 +{ + +/* + * Concatenation Kernel: + * + * Input_1(1, 4, 4, 1) Input_2(1, 4, 4, 2) + * \ / + * Concatenation + * | + * Output(1, 4, 4, 3) + */ +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x0c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input1_data = {-9, -22, -32, 7, -23, -8, -23, -32, + -31, -25, -8, -22, -23, 1, -24, -32}; +const std::vector input2_data = {-29, -31, -8, -23, 16, -23, -38, 7, -36, -22, -32, + -24, -23, -18, -33, -23, -38, -24, -38, -14, -16, -13, + -15, -22, -38, -53, -5, -40, -23, -22, -23, -41}; +const std::vector reference_output_data = { + -9, -29, -31, -22, -8, -23, -32, 16, -23, 7, -38, 7, -23, -36, -22, -8, + -32, -24, -23, -23, -18, -32, -33, -23, -31, -38, -24, -25, -38, -14, -8, -16, + -13, -22, -15, -22, -23, -38, -53, 1, -5, -40, -24, -23, -22, -32, -23, -41}; + +} // namespace concatenation_s8 + +class TestDataS8Concatenation : public TestDataConcatenationBase +{ +public: + TestDataS8Concatenation() + { + _input1_data = concatenation_s8::input1_data; + _input2_data = concatenation_s8::input2_data; + _reference_output_data = concatenation_s8::reference_output_data; + _test_kernel_model_circle = concatenation_s8::test_kernel_model_circle; + } + + ~TestDataS8Concatenation() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_CONCATENATION_KERNEL_S8_H diff --git a/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h b/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h index a240cdfd86c..9cf0f4ebfaf 100644 --- a/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h +++ b/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h @@ -160,6 +160,60 @@ const unsigned char test_kernel_model_circle[] = { } // namespace neg_gather_wrong_axis +namespace neg_gather_scale_mismatch +{ +/* + * Gather Kernel with io quant scael mismatch + * + * Input(1, 2, 3, 4) - S8 (scale 0.38) Indices(1, 2) + * \ / + * Gather(axis=2) + * | + * Output(1, 2, 2, 4) (scale 0.8) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, 0x4c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xb8, 0x1e, 0x05, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + 0x05, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +} // namespace neg_gather_scale_mismatch + class NegTestDataInputOutputTypeMismatchGatherKernel : public NegTestDataBase { public: @@ -208,6 +262,22 @@ class NegTestDataWrongAxisGatherKernel : public NegTestDataBase const unsigned char *_test_kernel_model_circle; }; +class NegTestDataInputOutputScaleMismatchGatherKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputScaleMismatchGatherKernel() + { + _test_kernel_model_circle = neg_gather_scale_mismatch::test_kernel_model_circle; + } + + ~NegTestDataInputOutputScaleMismatchGatherKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + } // namespace test_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h b/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h new file mode 100644 index 00000000000..a3bbc5e9127 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_GATHER_S8_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_GATHER_S8_KERNEL_H + +#include "TestDataGatherBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace gather_s8 +{ +/* + * Gather Kernel: + * + * Input(1, 2, 3, 4) Indices(1, 2) + * \ / + * Gather(axis=2) + * | + * Output(1, 2, 2, 4) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, 0x4c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + 0x05, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00 + +}; + +const std::vector input_data = {4, 14, 14, 22, 5, -5, -4, -3, 5, 15, 13, 5, + -3, 5, -13, 15, -6, -13, -4, -12, -5, 5, 5, -5}; + +const std::vector reference_output_data = {5, -5, -4, -3, 5, 15, 13, 5, + -6, -13, -4, -12, -5, 5, 5, -5}; + +} // namespace gather_s8 + +class TestDataS8Gather : public TestDataGatherBase +{ +public: + TestDataS8Gather() + { + _input_data = gather_s8::input_data; + _reference_output_data = gather_s8::reference_output_data; + _test_kernel_model_circle = gather_s8::test_kernel_model_circle; + } + + ~TestDataS8Gather() override = default; +}; +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_GATHER_S8_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h b/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h new file mode 100644 index 00000000000..f2762487cd9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_LESS_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_LESS_KERNEL_S8_H + +#include "TestDataLessBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace less_s8_with_no_broadcasting +{ + +/* + * Less Kernel: + * + * Input_1(1, 1, 4, 3) Input_2(1, 1, 4, 3) + * scale: 0.0078431373 scale: 0.008431373 + * \ / + * Less(no broadcast) + * | + * Output(1, 1, 4, 3) + */ + +const unsigned char test_kernel_model_circle[] = { + + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x2c, + 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x8c, 0xff, 0xff, + 0xff, 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, + 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, + 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, + 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, + 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xbe, 0x23, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, + 0x00, 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x81, 0x80, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, + 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00 + +}; +const std::vector input1_data = {36, 4, 49, 84, 22, 40, 74, 97, 25, 26, 69, 37}; + +const std::vector input2_data = {66, 62, 58, 89, 2, 29, 37, 88, 64, 83, 73, 33}; + +const std::vector reference_output_data = {true, true, true, true, false, false, + false, false, true, true, true, false}; + +} // namespace less_s8_with_no_broadcasting + +namespace neg_less_s8_with_no_broadcasting +{ + +/* + * Less Kernel with input type mismatch: + * + * Input_1(1, 2, 2, 3) INT8 Input_2(1, 2, 2, 3) UINT8 + * \ / + * Less(no broadcast) + * | + * Output(1, 2, 2, 3) + */ + +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x8c, 0xff, 0xff, 0xff, 0x90, 0xff, 0xff, 0xff, + 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xbe, 0x23, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x81, 0x80, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +const std::vector input1_data = {36, 4, 49, 84, 22, 40, 74, 97, 25, 26, 69, 37}; + +const std::vector input2_data = {66, 62, 58, 89, 2, 29, 37, 88, 64, 83, 73, 33}; + +const std::vector reference_output_data = {true, true, true, true, false, false, + false, false, true, true, true, false}; + +} // namespace neg_less_s8_with_no_broadcasting + +class TestDataS8Less : public TestDataLessBase +{ +public: + explicit TestDataS8Less(bool is_with_broadcast, bool is_neg) + : TestDataLessBase(is_with_broadcast) + { + if (is_with_broadcast) + { + assert(false && "Not impl yet"); + } + else + { + if (is_neg) + { + _input1_data = neg_less_s8_with_no_broadcasting::input1_data; + _input2_data = neg_less_s8_with_no_broadcasting::input2_data; + _reference_output_data = neg_less_s8_with_no_broadcasting::reference_output_data; + _test_kernel_model_circle = neg_less_s8_with_no_broadcasting::test_kernel_model_circle; + } + else + { + _input1_data = less_s8_with_no_broadcasting::input1_data; + _input2_data = less_s8_with_no_broadcasting::input2_data; + _reference_output_data = less_s8_with_no_broadcasting::reference_output_data; + _test_kernel_model_circle = less_s8_with_no_broadcasting::test_kernel_model_circle; + } + } + } + + ~TestDataS8Less() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_LESS_KERNEL_QUANT_H diff --git a/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h b/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h new file mode 100644 index 00000000000..333fe228ab9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_S8_LOGISTIC_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_LOGISTIC_KERNEL_H + +#include "TestDataLogisticBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace logistic_s8 +{ +/* + * Logistic Kernel: + * + * Input(1, 1, 2, 2) : zp = -128, scale 1/256.0 by tflite quant spec + * | + * Logistic + * | + * Output(1, 1, 2, 2) zp = -128, scale 1/256.0 by tflite quant spec + */ +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, + 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = {-10, -5, 8, 99}; +const std::vector reference_output_data = {29, 30, 33, 53}; + +} // namespace logistic_s8 + +class TestDataS8Logistic : public TestDataLogisticBase +{ +public: + TestDataS8Logistic() + { + _input_data = logistic_s8::input_data; + _reference_output_data = logistic_s8::reference_output_data; + _test_kernel_model_circle = logistic_s8::test_kernel_model_circle; + } + + ~TestDataS8Logistic() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_LOGISTIC_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/pack/PackKernel.h b/onert-micro/onert-micro/include/test_models/pack/PackKernel.h index e2896d467b7..d7de7b0eb2b 100644 --- a/onert-micro/onert-micro/include/test_models/pack/PackKernel.h +++ b/onert-micro/onert-micro/include/test_models/pack/PackKernel.h @@ -221,6 +221,67 @@ const std::vector reference_output_data = { 5, 5, 5, 5, 5, 245, 251, 5, 251, 223, 5, 251, 22, 15, 15, 15}; } // namespace pack_quant_u8 +namespace pack_s8 +{ +/* + * Pack Kernel: + * + * Input(2, 2) Input(2, 2) + * \ / + * \ / + * Pack : values_count: 2, axis: 1 + * | + * Output(2, 2, 2) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x14, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x63, + 0x6b, 0x5f, 0x34, 0x64, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x84, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +const std::vector input_data_1 = {1, 2, 3, 4}; + +const std::vector input_data_2 = {5, 6, 7, 8}; + +const std::vector reference_output_data = {1, 2, 5, 6, 3, 4, 7, 8}; +} // namespace pack_s8 class TestDataFloatPack : public TestDataPackBase { @@ -264,6 +325,20 @@ class TestDataQuantU8Pack : public TestDataPackBase ~TestDataQuantU8Pack() override = default; }; +class TestDataS8Pack : public TestDataPackBase +{ +public: + TestDataS8Pack() + { + _input_data_1 = pack_s8::input_data_1; + _input_data_2 = pack_s8::input_data_2; + _reference_output_data = pack_s8::reference_output_data; + _test_kernel_model_circle = pack_s8::test_kernel_model_circle; + } + + ~TestDataS8Pack() override = default; +}; + } // namespace test_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h b/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h new file mode 100644 index 00000000000..b3e0068544d --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_QUANTIZE_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace quantize_float +{ +/* + * Quantize Kernel: + * + * Input(4) + * | + * Quantize + * | + * Output(4) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x9c, 0xc4, 0x20, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = {-16.784391, -1.0657115, -2.8470368, 15.907914}; + +const std::vector reference_output_data = {-7, 0, -1, 6}; +} // namespace quantize_float + +class TestDataFloatQuantize : public TestDataQuantizeBase +{ +public: + TestDataFloatQuantize() + { + _input_data = quantize_float::input_data; + _reference_output_data = quantize_float::reference_output_data; + _test_kernel_model_circle = quantize_float::test_kernel_model_circle; + } + + ~TestDataFloatQuantize() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_DEQUANTIZE_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h b/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h new file mode 100644 index 00000000000..06a3a4b895c --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_NEG_QUANTIZE_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_invalid_output_shape_quantize_kernel +{ +/* + * Quantize Kernel with invalid input shape - should be the same: + * + * Input(4) + * | + * Dequantize + * | + * Output(4, 3) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9c, 0xc4, 0x20, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +} // namespace neg_invalid_output_shape_quantize_kernel + +class NegTestDataWithInvalidOutputShapeQuantizeKernel : public NegTestDataBase +{ +public: + NegTestDataWithInvalidOutputShapeQuantizeKernel() + { + _test_kernel_model_circle = neg_invalid_output_shape_quantize_kernel::test_kernel_model_circle; + } + + ~NegTestDataWithInvalidOutputShapeQuantizeKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_NEG_QUANTIZE_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h b/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h new file mode 100644 index 00000000000..ed8a981956f --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_QUANTIZE_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_QUANTIZE_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataQuantizeBase : public TestDataBase +{ +public: + TestDataQuantizeBase() = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + + const std::vector &get_input_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _input_data; + default: + assert(false && "Wrong input index"); + } + } + + const std::vector &get_output_data_by_index(int i) override final + { + assert(i == 0); + return _reference_output_data; + } + +protected: + std::vector _input_data; + std::vector _reference_output_data; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_QUANTIZE_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h b/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h index d0c9c762be6..d6b14f6db3f 100644 --- a/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h +++ b/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h @@ -169,6 +169,172 @@ template class TestDataReshapeKernel : public TestDataBase const unsigned char *_test_kernel_model_circle; }; +namespace reshape_kernel_s8 +{ +/* + * Reshape Kernel: + * + * Input(1, 1, 1, 10) Const([1,10]) + * \ / + * Reshape + * | + * Output(1,10) + */ +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x54, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00 + +}; + +const std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const std::vector reference_output_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +} // namespace reshape_kernel_s8 + +namespace neg_reshape_kernel_s8 +{ +/* + * Reshape Kernel: + * + * Input(1, 1, 1, 10) Const([1, 10]) + * \ / + * Reshape + * | + * Output(1, 20) + */ +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x54, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00 + +}; + +const std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const std::vector reference_output_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +} // namespace neg_reshape_kernel_s8 + +class TestDataS8ReshapeKernel : public TestDataBase +{ +public: + TestDataS8ReshapeKernel(bool is_neg) + { + if (not is_neg) + { + _input_data = reshape_kernel_s8::input_data; + _reference_output_data = reshape_kernel_s8::reference_output_data; + _test_kernel_model_circle = reshape_kernel_s8::test_kernel_model_circle; + } + else + { + _input_data = neg_reshape_kernel_s8::input_data; + _reference_output_data = neg_reshape_kernel_s8::reference_output_data; + _test_kernel_model_circle = neg_reshape_kernel_s8::test_kernel_model_circle; + } + } + + ~TestDataS8ReshapeKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + + const std::vector &get_input_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _input_data; + default: + assert(false && "Wrong input index"); + } + } + + const std::vector &get_output_data_by_index(int i) override final + { + assert(i == 0); + return _reference_output_data; + } + +protected: + std::vector _input_data; + std::vector _reference_output_data; + const unsigned char *_test_kernel_model_circle; +}; + } // namespace test_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h b/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h index c36b24da231..c0d02ff2d9d 100644 --- a/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h +++ b/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h @@ -81,6 +81,76 @@ class NegTestDataInputOutputTypeMismatchSpaceToDepthKernel : public NegTestDataB const unsigned char *_test_kernel_model_circle; }; +namespace neg_input_output_shape_mismatch_space_to_depth_kernel +{ +/* + * SpaceToDepth kernel with input output shape mismatch: + * + * Input(1, 4, 4, 3) - S8 + * | + * SpaceToDepth + * | + * Output(1, 2, 3, 11) - S8 + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, + 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, + 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x11, 0x00, 0x00, 0x00, 0x4f, + 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, + 0x65, 0x00, 0x00, 0x00 + +}; +} // namespace neg_input_output_shape_mismatch_space_to_depth_kernel + +class NegTestDataInputOutputShapeMismatchSpaceToDepthKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputShapeMismatchSpaceToDepthKernel() + { + _test_kernel_model_circle = + neg_input_output_shape_mismatch_space_to_depth_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputShapeMismatchSpaceToDepthKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + } // namespace test_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h b/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h new file mode 100644 index 00000000000..8dc58e017d7 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_S8_SPACE_TO_DEPTH_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_SPACE_TO_DEPTH_KERNEL_H + +#include "TestDataSpaceToDepthBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace space_to_depth_s8 +{ +/* + * SpaceToDepth Kernel: + * + * Input(1, 4, 4, 3) + * | + * SpaceToDepth + * | + * Output(1, 2, 2, 12) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +const std::vector input_data = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; +const std::vector reference_output_data = { + 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 6, 7, 8, 9, 10, 11, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 30, 31, 32, 33, 34, 35, 42, 43, 44, 45, 46, 47}; +} // namespace space_to_depth_s8 + +class TestDataS8SpaceToDepth : public TestDataSpaceToDepthBase +{ +public: + TestDataS8SpaceToDepth() + { + _input_data = space_to_depth_s8::input_data; + _reference_output_data = space_to_depth_s8::reference_output_data; + _test_kernel_model_circle = space_to_depth_s8::test_kernel_model_circle; + } + + ~TestDataS8SpaceToDepth() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_SPACE_TO_DEPTH_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h b/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h index 29a0bc1781f..0da703d1ea7 100644 --- a/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h +++ b/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H -#define ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H +#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H #include "TestDataSplitBase.h" @@ -100,4 +100,4 @@ class TestDataFloatSplit : public TestDataSplitBase } // namespace test_model } // namespace onert_micro -#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h b/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h new file mode 100644 index 00000000000..8ebf00861e4 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_V_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_V_KERNEL_H + +#include "TestDataSplitVBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace split_v_kernel +{ +/* + * SplitV Kernel: + * + * Input(6, 1, 2) Size_splits([1, 2, 3]) Split_dim(scalar=0) + * \ | / + * SplitV + * / | \ + * Output(1, 1, 2) Output(2, 1, 2) Output(3, 1, 2) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x48, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x74, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x64, 0x69, 0x6d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x70, 0x6c, + 0x69, 0x74, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = {-3.9030151, -4.558613, -12.806297, -2.64188, + 17.035677, 26.150639, -12.618465, 0.8286438, + -4.850197, -0.20810127, 3.8918018, 4.1862106}; + +const std::vector reference_output_data_1 = {-3.9030151, -4.558613}; +const std::vector reference_output_data_2 = {-12.806297, -2.64188, 17.035677, 26.150639}; +const std::vector reference_output_data_3 = {-12.618465, 0.8286438, -4.850197, + -0.20810127, 3.8918018, 4.1862106}; + +} // namespace split_v_kernel + +class TestDataFloatSplitV : public TestDataSplitVBase +{ +public: + TestDataFloatSplitV() + { + _input_data = split_v_kernel::input_data; + _reference_output_data_1 = split_v_kernel::reference_output_data_1; + _reference_output_data_2 = split_v_kernel::reference_output_data_2; + _test_kernel_model_circle = split_v_kernel::test_kernel_model_circle; + } + + ~TestDataFloatSplitV() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_V_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h b/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h new file mode 100644 index 00000000000..10b7f052336 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_NEG_SPLITV_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_SPLITV_KERNEL_H + +#include "TestDataSplitVBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_input_output_type_mismatch_splitv_kernel +{ +/* + * SplitV Kernel input output type mismatch: should be the sa,e: + * + * Input(6, 1, 2) Size_splits([1, 2, 3]) Split_dim(scalar=0) + * \ | / + * SplitV + * / | \ + * Output(1, 1, 2)-INT32 Output(2, 1, 2) Output(3, 1, 2) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0c, 0x01, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xa8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xd8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x64, 0x69, + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, + 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x66, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, + 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +} // namespace neg_input_output_type_mismatch_splitv_kernel + +class NegTestDataInputOutputTypeMismatchSplitVKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchSplitVKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_splitv_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchSplitVKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_NEG_SPLIT_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h b/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h new file mode 100644 index 00000000000..674a68a3ef6 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_SPLITV_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_SPLITV_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataSplitVBase : public TestDataBase +{ +public: + TestDataSplitVBase() = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + + const std::vector &get_input_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _input_data; + default: + assert(false && "Wrong input index"); + } + } + + const std::vector &get_output_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _reference_output_data_1; + case 1: + return _reference_output_data_2; + default: + assert(false && "Wrong input index"); + } + } + +protected: + std::vector _input_data; + std::vector _reference_output_data_1; + std::vector _reference_output_data_2; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SPLITV_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h b/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h new file mode 100644 index 00000000000..276ba9eb1b9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_SUB_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_SUB_KERNEL_S8_H + +#include "TestDataSubBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace sub_s8_no_broadcasting +{ + +/* + * Sub Kernel: + * + * Input_1(2, 2) Input_2(2, 2) + * \ / + * Sub(w/o broadcast) + * | + * Output(2, 2) + */ + +unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x88, 0xff, 0xff, 0xff, 0x8c, 0xff, 0xff, 0xff, 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x0c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +std::vector input1_data = { + 5, + 7, + 13, + -3, +}; +std::vector input2_data = {-5, -11, 5, 5}; +std::vector reference_output_data = {10, 18, 8, -8}; +} // namespace sub_s8_no_broadcasting + +class TestDataS8Sub : public TestDataSubBase +{ +public: + explicit TestDataS8Sub(bool is_with_broadcast) : TestDataSubBase(is_with_broadcast) + { + if (is_with_broadcast) + { + std::cerr << ("Sub S8 with broadcasting not supported yet!\n"); + } + else + { + _input1_data = sub_s8_no_broadcasting::input1_data; + _input2_data = sub_s8_no_broadcasting::input2_data; + _reference_output_data = sub_s8_no_broadcasting::reference_output_data; + _test_kernel_model_circle = sub_s8_no_broadcasting::test_kernel_model_circle; + } + } + + ~TestDataS8Sub() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SUB_KERNEL_S8_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h b/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h new file mode 100644 index 00000000000..0a445597b66 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H + +#include "TestDataSVDFBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace svdf_float +{ +/* + * SVDF Kernel: + * + * Input(1, 16) + * | + * SVDF + * | + * Output(1, 64) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x6c, 0x19, 0x00, 0x00, 0x50, 0x1b, 0x00, 0x00, 0x6c, 0x1b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x19, 0x00, 0x00, 0x4c, 0x19, 0x00, 0x00, 0x44, 0x19, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, + 0x1c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0xe6, 0xff, 0xff, + 0xe6, 0xf6, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x35, 0x99, 0x20, 0x3f, + 0xda, 0x4f, 0xd8, 0xbd, 0x67, 0xa6, 0x33, 0x3f, 0xbb, 0x81, 0x2a, 0x3f, 0x6d, 0x7d, 0x87, 0x3f, + 0x2d, 0xbd, 0x64, 0x3e, 0xa6, 0x1f, 0x50, 0x3f, 0x98, 0x2e, 0x03, 0xc0, 0xa4, 0x8d, 0xe5, 0x3f, + 0xe6, 0x11, 0xbc, 0x3f, 0x17, 0xc3, 0x70, 0xbf, 0x54, 0xca, 0x3d, 0x3f, 0x14, 0xdc, 0x1e, 0xbf, + 0xe1, 0x81, 0x90, 0xbe, 0x8b, 0xa6, 0xf8, 0x3f, 0x5f, 0xbe, 0x79, 0x3e, 0x88, 0x81, 0xb2, 0xbf, + 0xf8, 0x40, 0x70, 0x3f, 0x7e, 0xc0, 0x0d, 0x40, 0x13, 0x79, 0x08, 0x3f, 0x16, 0xbf, 0xf4, 0x3e, + 0xfb, 0xd9, 0xa3, 0x3f, 0xd4, 0x08, 0x86, 0x3f, 0x14, 0xd3, 0xb8, 0x3e, 0xe5, 0x82, 0x36, 0x3f, + 0xb6, 0xd8, 0xdf, 0xbf, 0xfa, 0x99, 0x00, 0x3e, 0xcc, 0xb9, 0x42, 0x3f, 0x3e, 0x3a, 0x29, 0xbf, + 0x1c, 0x2a, 0xa4, 0xbe, 0x4d, 0x34, 0x4c, 0x3f, 0x2f, 0x5b, 0x0f, 0x3f, 0xe9, 0x7c, 0x1e, 0xbf, + 0x6d, 0x5a, 0x8f, 0x3f, 0x42, 0x07, 0xa8, 0x3f, 0x37, 0x59, 0x26, 0x3f, 0x4b, 0xf0, 0xe2, 0xbf, + 0x9b, 0x10, 0xaa, 0x3c, 0xd1, 0x74, 0x0b, 0xbf, 0xed, 0xfd, 0xe1, 0x3d, 0xd8, 0x76, 0x97, 0x3f, + 0x8e, 0x81, 0xd3, 0x3e, 0xc7, 0x97, 0x2e, 0x3f, 0x61, 0xf6, 0x0b, 0x3e, 0xd6, 0xff, 0x90, 0xbf, + 0x1f, 0xe6, 0x83, 0xbe, 0x8c, 0x42, 0x54, 0x3f, 0x3c, 0x95, 0x24, 0x3f, 0xd2, 0x7f, 0x94, 0xbf, + 0x2a, 0x18, 0xa5, 0xbf, 0xdc, 0x72, 0xa7, 0xbf, 0x2d, 0x54, 0x84, 0xbf, 0x88, 0xc1, 0xf7, 0xbe, + 0x7b, 0xe8, 0x99, 0xbe, 0x09, 0x21, 0xd2, 0x3f, 0x47, 0xa1, 0x92, 0xbf, 0x13, 0xa3, 0x52, 0x3f, + 0x5b, 0x23, 0x3f, 0x3f, 0xb2, 0xf2, 0xdd, 0xbf, 0x0c, 0xd7, 0x07, 0xbf, 0x68, 0xc5, 0x32, 0xbf, + 0x94, 0xbf, 0x30, 0x3e, 0x90, 0x1e, 0x55, 0x3f, 0x96, 0x51, 0x28, 0xbf, 0xf2, 0xf7, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x6e, 0x8f, 0x3c, 0x43, 0x1d, 0xc2, 0x3e, + 0x4a, 0xec, 0xc2, 0x3f, 0xce, 0x89, 0x27, 0x3e, 0xd9, 0xe0, 0x2c, 0xbf, 0xe4, 0x54, 0x22, 0xbf, + 0xae, 0x26, 0xb4, 0xbe, 0x81, 0xf4, 0x49, 0x3e, 0x87, 0x1c, 0xf6, 0xbe, 0xd9, 0x78, 0x1b, 0xbf, + 0x2b, 0xa6, 0xd3, 0x3f, 0x25, 0x20, 0x3e, 0x3f, 0xd6, 0x2c, 0xa7, 0x3f, 0x62, 0xed, 0x0c, 0x3f, + 0x20, 0x6e, 0xc6, 0x3e, 0x87, 0x31, 0x10, 0xc0, 0xf1, 0x84, 0x50, 0xbf, 0x22, 0xf6, 0x03, 0xbf, + 0xff, 0x80, 0xf1, 0xbf, 0x65, 0xfc, 0x82, 0xbf, 0x37, 0x0b, 0x01, 0xc0, 0x90, 0x38, 0x98, 0x3f, + 0x03, 0x5a, 0xa9, 0xbf, 0x0b, 0x95, 0x9d, 0x3e, 0x5c, 0xb7, 0x70, 0x3f, 0x9d, 0xff, 0x65, 0x3f, + 0x99, 0x25, 0xa6, 0x3e, 0xbd, 0x5c, 0x84, 0x3e, 0xa9, 0xb4, 0x50, 0xbf, 0xae, 0x70, 0x4e, 0x3f, + 0x60, 0x8c, 0x83, 0x3f, 0xd0, 0xc5, 0xc6, 0x3f, 0x7b, 0x70, 0xd0, 0x3d, 0xa9, 0xc1, 0x76, 0xbf, + 0x39, 0x37, 0xb2, 0xbe, 0xea, 0x40, 0xbd, 0xbd, 0x31, 0x2b, 0x86, 0x3f, 0xb6, 0x28, 0xc5, 0xbf, + 0x92, 0x9a, 0x8e, 0x3e, 0x86, 0x10, 0x1c, 0x3e, 0xd8, 0x24, 0x9e, 0xbf, 0xac, 0x22, 0xa1, 0x3d, + 0x78, 0xee, 0xed, 0xbf, 0x68, 0xce, 0x1d, 0x40, 0xf6, 0x1b, 0xdf, 0x3e, 0x97, 0x10, 0x44, 0x3e, + 0x52, 0xde, 0x19, 0x3f, 0x1c, 0xbd, 0xfd, 0xbf, 0xa1, 0x64, 0x4c, 0x3f, 0x1b, 0xaa, 0x00, 0xbf, + 0x36, 0xa7, 0x11, 0xbe, 0x6e, 0xdf, 0x9b, 0xbf, 0x3d, 0xc8, 0x11, 0x40, 0xda, 0x8f, 0xc9, 0x3f, + 0x36, 0x26, 0x99, 0xbf, 0x54, 0x0f, 0x7a, 0x3f, 0x3e, 0x41, 0x64, 0x3d, 0xc5, 0xd4, 0x54, 0xc0, + 0xb2, 0x18, 0xa6, 0x3e, 0xd3, 0xed, 0x3c, 0xbe, 0xea, 0x0c, 0x7f, 0xbf, 0xf6, 0xd5, 0xd7, 0xbe, + 0xf8, 0x29, 0x65, 0xbd, 0x79, 0x6e, 0x6a, 0xbf, 0x78, 0x61, 0xde, 0x3f, 0x18, 0xef, 0x7d, 0xbf, + 0xde, 0x29, 0x42, 0x3f, 0x21, 0xfc, 0x0c, 0xbf, 0x90, 0x77, 0x82, 0x3f, 0x85, 0x5e, 0x14, 0xc0, + 0xfd, 0x7d, 0xf2, 0x3e, 0x3f, 0x7a, 0xc9, 0xbf, 0x70, 0x99, 0x5b, 0x3f, 0x63, 0xe9, 0x1c, 0x3e, + 0x29, 0x07, 0x95, 0xbe, 0xa9, 0x3e, 0x0e, 0x3f, 0x2f, 0x57, 0x67, 0x3e, 0x18, 0xe0, 0xb4, 0xbe, + 0xcb, 0x10, 0xe4, 0x3e, 0xc5, 0xd6, 0xa2, 0xbd, 0x7f, 0x1a, 0x59, 0x3e, 0xf3, 0x3b, 0x62, 0x3f, + 0xad, 0x5f, 0x18, 0x3f, 0x87, 0x9a, 0x52, 0x3e, 0x6c, 0x91, 0xc2, 0xbf, 0x32, 0xcc, 0xb9, 0xbf, + 0x17, 0x14, 0xc2, 0x3f, 0xed, 0xbb, 0x73, 0x3f, 0xe2, 0xba, 0x10, 0xbf, 0x62, 0x23, 0xc3, 0xbf, + 0x05, 0x41, 0xed, 0xbe, 0xc9, 0x13, 0xca, 0xbe, 0xa1, 0x7f, 0x8d, 0xbe, 0x1b, 0x08, 0x09, 0x3f, + 0xfe, 0xc7, 0x39, 0x3f, 0x41, 0x06, 0x0f, 0xc0, 0xdd, 0x06, 0xdb, 0x3f, 0x96, 0x5f, 0x07, 0x3e, + 0x37, 0x22, 0x66, 0xbf, 0x59, 0xf4, 0xfd, 0xbf, 0x00, 0x6f, 0x68, 0xbd, 0x2e, 0x62, 0x0f, 0xc0, + 0xf3, 0xb0, 0xc5, 0xbf, 0xb8, 0xaa, 0x62, 0xbf, 0x9b, 0x00, 0x4f, 0x3f, 0xec, 0xbd, 0xfe, 0x3e, + 0x4e, 0x7e, 0xc4, 0xbc, 0x8e, 0x8d, 0xa7, 0x3f, 0xef, 0xa5, 0xfb, 0xbf, 0xaf, 0x17, 0x92, 0xbf, + 0xe5, 0x98, 0xc5, 0xbf, 0x6d, 0x3a, 0x19, 0x3f, 0x25, 0x29, 0x57, 0xbf, 0x80, 0x58, 0x00, 0x3f, + 0x10, 0x21, 0x80, 0xbe, 0x19, 0x5c, 0x50, 0xbe, 0x4f, 0xb2, 0x71, 0x3f, 0x4b, 0xa0, 0x2f, 0x3f, + 0x0f, 0xcf, 0x82, 0xbd, 0x51, 0x86, 0x8b, 0x3f, 0x33, 0xa9, 0x83, 0xbf, 0xa4, 0x21, 0x53, 0x3e, + 0xae, 0x6a, 0x08, 0x3c, 0x23, 0xf4, 0xb6, 0x3f, 0xb2, 0x5b, 0xcc, 0x3e, 0xf3, 0xd1, 0x5c, 0x3f, + 0xea, 0x1c, 0xeb, 0x3e, 0xe9, 0x4e, 0x03, 0xbf, 0x30, 0x56, 0xe6, 0xbe, 0x17, 0xf5, 0xc4, 0xbd, + 0x94, 0x41, 0xcf, 0x3f, 0x0c, 0xb2, 0xec, 0x3f, 0xcb, 0xc5, 0x99, 0xbe, 0x05, 0x18, 0xa6, 0x3f, + 0x1d, 0x06, 0x1a, 0xbf, 0xbe, 0x1d, 0x0a, 0x40, 0xad, 0x0e, 0xb4, 0x3f, 0x51, 0xd6, 0x25, 0xbf, + 0x61, 0x87, 0xa7, 0xbf, 0x13, 0x07, 0x7a, 0x3e, 0xc6, 0x13, 0xe0, 0xbe, 0x1f, 0xfe, 0x42, 0xbf, + 0x26, 0x9c, 0x96, 0xbe, 0x15, 0x1f, 0xdf, 0x3e, 0x80, 0x11, 0x06, 0xbd, 0xf5, 0x7f, 0x03, 0x3d, + 0x9c, 0x46, 0x5f, 0xbe, 0xe9, 0x86, 0x2b, 0x3f, 0x3e, 0x82, 0x02, 0xc0, 0x70, 0xa4, 0xd9, 0x3f, + 0x05, 0xcf, 0xf8, 0xbe, 0xb3, 0x0a, 0x9d, 0xbf, 0x20, 0xfc, 0x87, 0xbf, 0xec, 0xe9, 0x1a, 0x3f, + 0x37, 0x5f, 0x4f, 0xbe, 0xc6, 0x3d, 0x0f, 0xbf, 0x9d, 0x72, 0xa4, 0xbf, 0x87, 0x45, 0x87, 0xbd, + 0xb8, 0xc2, 0x60, 0xbe, 0x65, 0x2e, 0xe0, 0x3f, 0x69, 0xaa, 0xbc, 0x3e, 0xb5, 0xc4, 0x2c, 0xbf, + 0x62, 0x2d, 0x4c, 0x3e, 0x5d, 0x10, 0x09, 0xbe, 0x75, 0xe9, 0x0e, 0xbf, 0x88, 0x3a, 0x46, 0x3e, + 0xd1, 0x5b, 0x86, 0x3f, 0x10, 0x73, 0x36, 0xbf, 0x8c, 0x9d, 0xfb, 0x3e, 0xd6, 0x35, 0xac, 0x3f, + 0x3b, 0x14, 0xe1, 0xbe, 0xab, 0xe9, 0xc0, 0x3f, 0x1c, 0x97, 0xe9, 0x3d, 0xdf, 0x26, 0xac, 0x3e, + 0x67, 0x88, 0x59, 0xbf, 0x4e, 0xf7, 0xb8, 0xbf, 0x52, 0x85, 0x46, 0x3f, 0xa7, 0x8b, 0x0c, 0x3f, + 0x2a, 0x14, 0x48, 0xbe, 0x13, 0x62, 0xe6, 0xbf, 0x5d, 0x88, 0x18, 0x3f, 0xea, 0x9c, 0x17, 0x40, + 0x20, 0x77, 0xb0, 0xbf, 0x71, 0xb1, 0x56, 0x3f, 0x4e, 0x88, 0xcc, 0xbf, 0x2f, 0x42, 0x00, 0x40, + 0x2d, 0x52, 0x4a, 0xbf, 0x08, 0x8d, 0xff, 0x3f, 0x6e, 0x6f, 0x05, 0x3f, 0xcc, 0x05, 0x5e, 0x3f, + 0xe0, 0x25, 0x24, 0x3f, 0xd0, 0xaf, 0x15, 0x40, 0xb7, 0x6a, 0xba, 0xbe, 0x51, 0xeb, 0x83, 0xbe, + 0x0b, 0x12, 0x58, 0x3e, 0x4e, 0x78, 0xe3, 0x3f, 0xcb, 0x34, 0xa1, 0x3f, 0xb6, 0xb4, 0x85, 0xbf, + 0x27, 0xf2, 0xf7, 0x3d, 0xee, 0x30, 0x27, 0xbf, 0x5f, 0xd1, 0x53, 0xbf, 0xf0, 0x42, 0x0c, 0xbf, + 0xa0, 0x57, 0xad, 0xbf, 0x47, 0x27, 0xcb, 0x3f, 0xfb, 0x02, 0xb5, 0x3e, 0x06, 0xb4, 0xfa, 0xbf, + 0xab, 0x85, 0x0c, 0x3f, 0x41, 0x8f, 0xb6, 0xbf, 0x01, 0xca, 0x1b, 0x3f, 0xd3, 0xf1, 0x48, 0x40, + 0x40, 0x4c, 0x01, 0x40, 0x60, 0xb3, 0x2c, 0x3f, 0x48, 0x48, 0xce, 0x3b, 0x6e, 0x7d, 0x50, 0x3e, + 0xe9, 0xbf, 0x6e, 0xbf, 0x5e, 0x24, 0x13, 0x3f, 0x65, 0x3a, 0x80, 0xbf, 0x07, 0x43, 0x86, 0x3e, + 0x66, 0x9d, 0x76, 0xbf, 0x46, 0xb3, 0x42, 0xbf, 0x3a, 0x69, 0xc9, 0xbf, 0xb8, 0x61, 0x6f, 0x3f, + 0xc8, 0xbd, 0xd4, 0x3f, 0x74, 0x73, 0x98, 0x3f, 0x92, 0x49, 0x05, 0xc0, 0xbe, 0x9d, 0xb5, 0x3e, + 0x9d, 0x72, 0x58, 0x3f, 0x12, 0x29, 0x78, 0x3d, 0x74, 0x96, 0xf1, 0xbe, 0x02, 0xab, 0x02, 0xbf, + 0xca, 0xf9, 0x18, 0xbe, 0xb0, 0x33, 0x6b, 0xbf, 0xd7, 0x1e, 0x89, 0xbf, 0xb0, 0xc5, 0x26, 0xbf, + 0x99, 0xcf, 0xd0, 0x3e, 0xb1, 0xae, 0x68, 0xbf, 0xb7, 0xc3, 0xd0, 0xbe, 0x1a, 0x33, 0x37, 0xbf, + 0x4d, 0xf8, 0x95, 0xbf, 0xb4, 0x3e, 0x8e, 0xbf, 0x25, 0x81, 0x6f, 0x3f, 0x78, 0x33, 0xd2, 0xbf, + 0x16, 0x3b, 0xf2, 0x3d, 0x8f, 0x27, 0x53, 0x3f, 0x08, 0x75, 0x27, 0x40, 0x2f, 0x89, 0xd1, 0xbe, + 0xd8, 0x59, 0xb8, 0x3e, 0x41, 0x36, 0x1a, 0xbf, 0xa5, 0x92, 0x01, 0x3e, 0x90, 0xef, 0xb9, 0x3f, + 0xcf, 0x82, 0x8d, 0xbf, 0x04, 0x60, 0x54, 0xbe, 0x93, 0xc2, 0xf1, 0x3f, 0xbb, 0x09, 0x36, 0xbf, + 0xf8, 0x6b, 0x59, 0x3f, 0x01, 0xa7, 0x8f, 0x3f, 0xd3, 0x11, 0x33, 0xbf, 0xed, 0x9d, 0xc7, 0x3f, + 0x55, 0x60, 0x1d, 0x3e, 0x46, 0xff, 0x08, 0xbf, 0xcf, 0xc5, 0xd3, 0xbf, 0x4c, 0xa6, 0x35, 0xbf, + 0x86, 0x41, 0x49, 0xbf, 0x56, 0xef, 0xb1, 0xbf, 0x2c, 0x62, 0x54, 0xbf, 0xe7, 0x81, 0x7a, 0x3f, + 0x38, 0x4b, 0x80, 0x3f, 0xd5, 0x37, 0xf3, 0xbf, 0x0c, 0x67, 0xa7, 0x3f, 0xb7, 0xbf, 0x32, 0x3e, + 0xa1, 0x05, 0x36, 0xbf, 0x0c, 0x7b, 0x95, 0x3f, 0x8d, 0xd0, 0x86, 0xbf, 0x3b, 0x74, 0xe9, 0xbe, + 0x02, 0x76, 0xb1, 0xbe, 0x6b, 0xbe, 0xb3, 0xbf, 0x12, 0xda, 0x8f, 0xbf, 0xc3, 0x7d, 0x2c, 0xbf, + 0x0a, 0x9a, 0x14, 0x3f, 0xf3, 0xbb, 0x77, 0x3f, 0x5d, 0x8f, 0x87, 0xbf, 0x2c, 0x03, 0xdc, 0x3f, + 0xc0, 0xb0, 0xd0, 0x3f, 0x7f, 0xde, 0x47, 0x3f, 0x02, 0xc0, 0x98, 0xbf, 0xec, 0x93, 0x08, 0xc0, + 0x8e, 0x78, 0x9f, 0x3f, 0x27, 0xc5, 0x85, 0x3f, 0xa1, 0x13, 0x40, 0x3f, 0x77, 0xec, 0xc5, 0xbf, + 0x88, 0x7a, 0x6d, 0xbe, 0x96, 0xa1, 0xa9, 0xbf, 0x0e, 0x67, 0xb9, 0x3f, 0xa0, 0x0e, 0xa9, 0xbf, + 0x61, 0xce, 0x4c, 0x3f, 0xcb, 0xd4, 0x73, 0xbf, 0xf6, 0x2d, 0xb6, 0x3e, 0xa0, 0xd3, 0xb4, 0xbf, + 0x42, 0x20, 0x21, 0xbf, 0xf3, 0xf2, 0x00, 0xbf, 0xe3, 0x01, 0x92, 0x3f, 0x19, 0x4f, 0x3f, 0xbf, + 0xb4, 0x47, 0x28, 0xbf, 0x22, 0xa3, 0x94, 0x3f, 0x90, 0x21, 0x9a, 0xbf, 0x35, 0xdd, 0x62, 0xbf, + 0x50, 0x78, 0x8b, 0xbe, 0x9e, 0xac, 0x7d, 0x3f, 0xb3, 0x12, 0xaf, 0x3f, 0x5b, 0x3e, 0xbb, 0x3d, + 0x85, 0xcf, 0x87, 0xbf, 0x51, 0xa3, 0xb5, 0x3f, 0x91, 0x6f, 0xbd, 0xbf, 0xb6, 0x66, 0x3a, 0xbf, + 0x0c, 0x74, 0xc1, 0x3f, 0xa6, 0x79, 0x0b, 0x3f, 0x77, 0x2f, 0x51, 0x3f, 0x3d, 0x3c, 0x51, 0xbf, + 0x3e, 0x83, 0x64, 0xbf, 0xab, 0x82, 0xd7, 0xbe, 0x2c, 0xdf, 0x9f, 0xbe, 0x73, 0x76, 0x1f, 0xbf, + 0x53, 0xfd, 0xf0, 0xbd, 0xec, 0xb5, 0x8a, 0xbf, 0x4b, 0xc8, 0x6e, 0xbf, 0xc6, 0xd2, 0xc4, 0x3e, + 0x27, 0xc9, 0x77, 0x3d, 0xce, 0x0e, 0x5a, 0x3e, 0x7d, 0xbe, 0x22, 0x3f, 0x5b, 0xc8, 0x9a, 0x3e, + 0xe4, 0x5f, 0x9b, 0x3f, 0x18, 0x35, 0x41, 0xbf, 0x5d, 0x5c, 0xd5, 0x3e, 0x46, 0x06, 0x43, 0xbe, + 0xb9, 0x0b, 0x80, 0x3f, 0x70, 0x5a, 0x47, 0x3f, 0xb6, 0x48, 0xa8, 0x3e, 0x5c, 0x5e, 0x24, 0xbf, + 0x8d, 0x46, 0x6c, 0xbe, 0x53, 0x39, 0xf7, 0xbe, 0xac, 0xae, 0x8a, 0xbe, 0x56, 0x69, 0xe2, 0xbf, + 0x1e, 0xb3, 0x85, 0x3f, 0x5a, 0x79, 0x75, 0xbf, 0x9e, 0x78, 0x16, 0x3f, 0xbf, 0xf0, 0x50, 0xbf, + 0x64, 0x26, 0x1e, 0xbd, 0xd4, 0x6a, 0x97, 0xbe, 0xf5, 0x47, 0xab, 0xbf, 0xca, 0x3a, 0x85, 0x3f, + 0x25, 0xbf, 0x58, 0xbf, 0x3c, 0x13, 0xf2, 0x3c, 0x0b, 0x0c, 0xa9, 0xbf, 0xea, 0xf8, 0xf8, 0x3f, + 0x8a, 0x5a, 0xe4, 0x3e, 0xa2, 0x6e, 0x44, 0xbf, 0x37, 0x66, 0x88, 0xbf, 0xa5, 0x52, 0xb2, 0xbf, + 0xef, 0x3f, 0xd5, 0xbf, 0x0b, 0x74, 0x31, 0xbe, 0x74, 0x86, 0x5b, 0xbf, 0x6f, 0x58, 0x5d, 0xbf, + 0x94, 0x04, 0xdc, 0x3f, 0xc4, 0x9e, 0x55, 0x3e, 0x3b, 0x18, 0x07, 0xbf, 0x8d, 0x07, 0x7a, 0x3f, + 0xb9, 0x29, 0x15, 0xc0, 0xc7, 0xa1, 0xd1, 0x3e, 0x3c, 0x44, 0x98, 0xbd, 0x60, 0xce, 0x09, 0xbf, + 0xf7, 0x72, 0x85, 0xbe, 0x38, 0x6e, 0x05, 0xc0, 0x98, 0xee, 0xc2, 0xbf, 0x45, 0x73, 0xaa, 0xbd, + 0x3c, 0xef, 0xc9, 0xbf, 0x13, 0x64, 0xb4, 0x3f, 0x26, 0x6b, 0x38, 0x3f, 0x52, 0x90, 0xca, 0xbf, + 0x9c, 0x66, 0xd1, 0x3f, 0x77, 0x8d, 0x2d, 0xbf, 0x84, 0xe2, 0x91, 0xbe, 0x9b, 0x02, 0x19, 0x3f, + 0x27, 0x9c, 0x82, 0xbf, 0x38, 0xb1, 0x77, 0x3f, 0x75, 0xbd, 0x5f, 0x3f, 0x30, 0xa6, 0x0c, 0xbd, + 0xc8, 0xc5, 0xa9, 0x3e, 0xba, 0x84, 0x40, 0xbe, 0xb6, 0x11, 0xd8, 0xbd, 0xdd, 0x1c, 0x27, 0xbf, + 0x63, 0x10, 0x0c, 0x40, 0xbc, 0xfc, 0x24, 0xbf, 0x70, 0xc8, 0x82, 0xbf, 0x5b, 0x57, 0x51, 0x3e, + 0x35, 0xb6, 0x86, 0x3f, 0xa2, 0x44, 0x0e, 0x40, 0xbf, 0x7e, 0x8c, 0x3e, 0x4c, 0x6b, 0x96, 0x3f, + 0xc0, 0x85, 0xcb, 0x3e, 0x64, 0x83, 0x86, 0xbf, 0xe3, 0x41, 0xed, 0x3e, 0x5f, 0x77, 0x27, 0xbd, + 0x9e, 0x94, 0xd2, 0x3f, 0xe0, 0x62, 0xa2, 0xbe, 0x78, 0xe5, 0xb5, 0xbe, 0xba, 0xfc, 0xed, 0xbe, + 0xfe, 0xd0, 0xe6, 0xbf, 0x33, 0xd5, 0xbd, 0xbe, 0xed, 0x7e, 0x7a, 0xbf, 0x75, 0x0e, 0xe6, 0x3e, + 0xf6, 0x05, 0x0d, 0x3f, 0x40, 0x53, 0x6c, 0x3e, 0xbe, 0xf3, 0x4a, 0xbe, 0x78, 0x92, 0x02, 0xbf, + 0x1e, 0x9a, 0xb3, 0x3e, 0x2f, 0x32, 0x94, 0xbf, 0x33, 0xb2, 0x46, 0xbf, 0x5b, 0x5f, 0x18, 0x3d, + 0x81, 0xe8, 0xa5, 0x3f, 0xf9, 0xeb, 0xa9, 0xbe, 0x2c, 0x46, 0x76, 0x3f, 0xf4, 0x34, 0x43, 0x3f, + 0xfe, 0x03, 0x75, 0x3f, 0x57, 0x4c, 0x97, 0x3f, 0xdc, 0x54, 0xb1, 0xbe, 0x68, 0x1b, 0xaa, 0x3f, + 0x82, 0xd0, 0xe5, 0x3f, 0x08, 0xa7, 0x1c, 0x3f, 0xbc, 0x1c, 0x5e, 0xbf, 0xba, 0x18, 0x74, 0xbf, + 0x48, 0xed, 0xc0, 0xbf, 0xd9, 0xf8, 0xbe, 0xbe, 0x0b, 0x86, 0x4a, 0xbf, 0x9b, 0x83, 0x51, 0x3c, + 0x0f, 0x9e, 0xba, 0x3e, 0xc9, 0x59, 0xca, 0xbf, 0x6a, 0x26, 0x6c, 0x3f, 0x35, 0xfa, 0x6d, 0x3f, + 0x15, 0xea, 0x3c, 0xbf, 0x26, 0xe8, 0x1b, 0x3e, 0x97, 0xec, 0x1a, 0xbf, 0x5e, 0x58, 0x86, 0x3e, + 0xdc, 0xed, 0x16, 0xbf, 0x6e, 0xc6, 0x1c, 0x3f, 0xee, 0xd4, 0x91, 0x3c, 0x4d, 0x2f, 0x6d, 0x3e, + 0x86, 0x76, 0x33, 0xbf, 0xdd, 0x07, 0xb2, 0x3f, 0x49, 0x01, 0x17, 0x3f, 0x5c, 0xc6, 0xd9, 0xbf, + 0x89, 0xf2, 0x5f, 0xbf, 0xbc, 0xe6, 0xea, 0xbe, 0x19, 0xec, 0x11, 0xbd, 0x50, 0x0b, 0xe5, 0x3d, + 0x73, 0x8b, 0xa5, 0x3e, 0xff, 0x41, 0x34, 0xbf, 0x0d, 0xa5, 0xb2, 0xbf, 0xef, 0x88, 0xdd, 0x3d, + 0x40, 0x66, 0x92, 0xbe, 0x1d, 0x5b, 0x22, 0xbf, 0x9c, 0x7f, 0xfb, 0x3d, 0x59, 0xfb, 0xc8, 0xbd, + 0x34, 0xe3, 0x47, 0x3e, 0x85, 0x8d, 0xf1, 0xbe, 0xb2, 0x56, 0xdf, 0xbe, 0x82, 0x67, 0x08, 0x3f, + 0x69, 0x40, 0xec, 0x3e, 0x48, 0x59, 0xd4, 0x3f, 0xc7, 0xac, 0xf1, 0x3e, 0x01, 0xe6, 0x48, 0xbe, + 0x51, 0xa7, 0x0b, 0xbf, 0xda, 0x0a, 0x54, 0xbf, 0x0a, 0x87, 0x91, 0x3f, 0x00, 0x86, 0x4d, 0xbf, + 0x4e, 0xba, 0xb5, 0x3f, 0xee, 0x28, 0xeb, 0x3f, 0x3d, 0xde, 0xb0, 0xbf, 0xc4, 0x0c, 0x69, 0xbe, + 0xc2, 0x91, 0xf9, 0xbd, 0x37, 0x7c, 0x6a, 0xbf, 0xd9, 0x9b, 0xbc, 0xbc, 0x46, 0x17, 0x09, 0xc0, + 0x5c, 0xa8, 0xd2, 0x3e, 0xb8, 0xfd, 0x3f, 0xbf, 0x25, 0x11, 0x90, 0x3f, 0xdc, 0x01, 0xa5, 0x3e, + 0xae, 0x16, 0x3e, 0xbf, 0xbb, 0xb4, 0x1b, 0x3f, 0x4c, 0x43, 0x5e, 0x3f, 0x96, 0xeb, 0x83, 0xbe, + 0x0b, 0xd6, 0x0f, 0x3f, 0xd9, 0xa2, 0xa8, 0xbc, 0x04, 0x25, 0x9d, 0x3f, 0x35, 0xc1, 0x32, 0xbf, + 0x22, 0x3f, 0x6b, 0xbf, 0x5b, 0x10, 0xff, 0xbd, 0x6c, 0xd2, 0x94, 0xbf, 0x6f, 0x8e, 0x97, 0xbf, + 0x36, 0x88, 0xd8, 0xbf, 0xf6, 0x1d, 0x49, 0xbf, 0xc0, 0x35, 0x50, 0x3f, 0x37, 0x39, 0x72, 0x3f, + 0x92, 0x97, 0x5f, 0x3e, 0xd3, 0xa8, 0x45, 0xbe, 0xef, 0x0a, 0x00, 0x3f, 0xd0, 0x2c, 0x03, 0xc0, + 0x6e, 0x1c, 0x4c, 0xbf, 0xb6, 0xd4, 0x22, 0x3f, 0x54, 0xfe, 0x05, 0x3f, 0xf9, 0x6e, 0x44, 0x3f, + 0xed, 0x1b, 0x27, 0xc0, 0x7b, 0x39, 0x84, 0x3e, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x8c, 0x6e, 0x1a, 0xbe, + 0x55, 0x01, 0xb5, 0x3f, 0xd3, 0x3f, 0x3d, 0xbf, 0x05, 0x55, 0x2e, 0x3f, 0xb9, 0xf7, 0x3f, 0xbf, + 0xcf, 0x42, 0x9e, 0xbf, 0x6b, 0xff, 0x7a, 0xbe, 0x9d, 0x11, 0x7f, 0xbf, 0xe1, 0xe9, 0x32, 0xbf, + 0x91, 0xaa, 0x7b, 0xbf, 0x54, 0xa4, 0xb7, 0x3b, 0x77, 0x80, 0xa9, 0xbd, 0x1d, 0xfc, 0x6d, 0xbf, + 0xf4, 0x7d, 0x86, 0xbf, 0x43, 0x92, 0x49, 0x3e, 0x3d, 0x0d, 0x60, 0x3f, 0x77, 0xbf, 0x08, 0x40, + 0x12, 0x2d, 0x71, 0x3d, 0xf9, 0xca, 0xc6, 0x3f, 0xb8, 0x57, 0x05, 0xc0, 0xec, 0xe0, 0x02, 0x3f, + 0x40, 0x33, 0x25, 0x3f, 0x13, 0x97, 0x67, 0x3e, 0x33, 0x1e, 0x80, 0xbe, 0xb4, 0xe6, 0x15, 0xbf, + 0x62, 0x11, 0x82, 0xbf, 0x34, 0x91, 0x83, 0x3f, 0x8c, 0x38, 0xe8, 0xbd, 0xf5, 0x3e, 0x90, 0xbf, + 0xcf, 0x66, 0x49, 0x3f, 0x8d, 0xa2, 0xc0, 0x3f, 0x76, 0x3a, 0xc7, 0x3e, 0x6e, 0xcf, 0x9f, 0x3f, + 0xf4, 0x0c, 0xc0, 0xbe, 0xbe, 0x83, 0xc5, 0xbf, 0xfd, 0xb3, 0xa8, 0x3e, 0xca, 0x78, 0x83, 0x3f, + 0x95, 0x08, 0x46, 0xbe, 0x97, 0xa6, 0x40, 0x3f, 0xf2, 0x5e, 0xaf, 0xbe, 0x4e, 0x27, 0x0c, 0xc0, + 0xe7, 0xd0, 0x03, 0x3f, 0x5e, 0x09, 0x74, 0xbf, 0x03, 0x93, 0xd2, 0x3e, 0xc0, 0xfa, 0x01, 0x3f, + 0xb7, 0xea, 0xd4, 0xbf, 0xd4, 0xad, 0xcf, 0x3d, 0xdf, 0x2f, 0xff, 0xbf, 0x16, 0xc5, 0x27, 0xbf, + 0xf3, 0x69, 0xff, 0xbe, 0xb0, 0x4b, 0xb9, 0xbf, 0x25, 0xa2, 0x92, 0x3c, 0xb0, 0xf7, 0xf0, 0x3f, + 0x0e, 0x74, 0x95, 0x3f, 0xb0, 0x75, 0x84, 0x3f, 0x88, 0x54, 0x18, 0x3f, 0x29, 0xa2, 0x6c, 0xbd, + 0x0c, 0x49, 0x29, 0xbf, 0xf7, 0x5b, 0xb1, 0x3f, 0x3e, 0x6a, 0x17, 0x3f, 0x2d, 0xe8, 0x0c, 0xbf, + 0x87, 0xc6, 0x48, 0xbf, 0x71, 0x80, 0xc5, 0x3e, 0x51, 0x27, 0x0e, 0x3e, 0x80, 0xb2, 0x1b, 0x40, + 0x19, 0xe3, 0xc8, 0x3e, 0x29, 0x9e, 0xb1, 0xbe, 0xe6, 0x2a, 0x40, 0xbf, 0x2f, 0xc3, 0x1c, 0xc0, + 0xc5, 0x83, 0xbf, 0xbe, 0xfb, 0x70, 0xb4, 0xbf, 0x6a, 0xa7, 0x49, 0xbf, 0x4c, 0x7a, 0x9d, 0xbf, + 0xc9, 0x3c, 0xd0, 0x3e, 0x0b, 0x76, 0xa8, 0xbe, 0x78, 0xe0, 0xd4, 0x3e, 0xa8, 0x00, 0xad, 0xbf, + 0x44, 0xb5, 0x94, 0x3f, 0x36, 0xd5, 0x9c, 0xbd, 0xb6, 0xe7, 0xaf, 0x3e, 0x14, 0xcc, 0x1f, 0xbe, + 0x26, 0x1b, 0xae, 0xbf, 0x63, 0xdf, 0xe3, 0x3d, 0x90, 0xff, 0x27, 0xbe, 0xc5, 0x77, 0x92, 0xbd, + 0x6d, 0x7a, 0x61, 0xbf, 0x55, 0x50, 0x9c, 0x3d, 0x5f, 0x74, 0x4a, 0x3c, 0x1f, 0x2f, 0x80, 0x3d, + 0x92, 0xa6, 0xb4, 0xbf, 0xe4, 0x5f, 0x49, 0xbf, 0x61, 0xfb, 0x3d, 0x3f, 0xf0, 0x12, 0x96, 0x3f, + 0xe6, 0x94, 0xd9, 0xbf, 0xe2, 0x8e, 0xa2, 0x3f, 0x18, 0x65, 0xee, 0x3e, 0x2c, 0x7d, 0x0d, 0xbe, + 0x9d, 0xb3, 0xda, 0x3f, 0x71, 0x09, 0x8f, 0x3e, 0xd0, 0xd0, 0xe0, 0xbf, 0x36, 0x43, 0x3f, 0x3e, + 0x44, 0xc5, 0x0b, 0x3f, 0xe5, 0x1a, 0x19, 0xbf, 0x0a, 0x90, 0x00, 0x3f, 0xe0, 0x15, 0xe2, 0x3e, + 0x5c, 0xf6, 0xd4, 0x3e, 0x2b, 0x27, 0x89, 0x3c, 0xc9, 0x33, 0xf5, 0x3e, 0x7e, 0x7f, 0x2c, 0x3f, + 0xcb, 0xda, 0xdd, 0x3f, 0x61, 0x32, 0xed, 0xbf, 0xde, 0x93, 0xdc, 0xbe, 0xfe, 0x17, 0x0a, 0x3e, + 0xe9, 0xd5, 0x65, 0xbd, 0xf4, 0xd9, 0x94, 0xbf, 0xa5, 0x6b, 0xaa, 0xbd, 0x80, 0xa2, 0x1b, 0x3f, + 0xa6, 0xdb, 0xa3, 0xbf, 0xd9, 0xb7, 0x8d, 0xbf, 0xec, 0xf1, 0x49, 0xbf, 0xef, 0x4f, 0x28, 0xbf, + 0x74, 0x4e, 0x19, 0x3f, 0xed, 0x71, 0xd1, 0xbf, 0x5c, 0x6e, 0xa0, 0xbf, 0xc0, 0x5b, 0xe2, 0xbe, + 0x8f, 0xf2, 0xc9, 0x3e, 0x30, 0x1f, 0x2b, 0xbe, 0x0f, 0x96, 0xfb, 0xbf, 0xa3, 0x49, 0xfb, 0x3f, + 0x23, 0x34, 0x8b, 0x3f, 0xbd, 0x38, 0x77, 0xbe, 0x9f, 0x90, 0x07, 0x3f, 0x9f, 0xdf, 0xab, 0x3e, + 0x91, 0xaa, 0xc2, 0xbf, 0xfb, 0x33, 0x0d, 0xbf, 0x42, 0x52, 0x95, 0xbe, 0xf7, 0x52, 0x51, 0x3f, + 0x83, 0x3e, 0xa3, 0x3e, 0x5c, 0x26, 0xe5, 0x3e, 0x4f, 0x14, 0xc0, 0x3e, 0x88, 0xdf, 0xcf, 0xbf, + 0xc9, 0xdc, 0x5b, 0x3f, 0x1f, 0xa9, 0x53, 0x3f, 0x91, 0x66, 0xa4, 0x3f, 0xab, 0xfe, 0x79, 0x3e, + 0xe3, 0xce, 0x66, 0x3f, 0x6a, 0xa9, 0x0f, 0xc0, 0x32, 0x12, 0x9a, 0x3f, 0x97, 0xee, 0x35, 0x3f, + 0xc8, 0x0b, 0x56, 0x3e, 0x82, 0xd5, 0xa1, 0xbe, 0xc8, 0x5d, 0x5d, 0xbd, 0x06, 0x1f, 0x02, 0x3f, + 0x65, 0x32, 0x33, 0x40, 0xd2, 0xa2, 0x2f, 0xbf, 0xb9, 0xca, 0x92, 0x3d, 0x4b, 0xea, 0xc9, 0x3f, + 0xf7, 0x3e, 0xce, 0x3e, 0xf2, 0x8f, 0x0a, 0xbe, 0x66, 0xcb, 0xe5, 0x3e, 0x7a, 0x98, 0x89, 0x3f, + 0x04, 0x8a, 0xc8, 0xbe, 0xbe, 0x83, 0xbe, 0x3f, 0x13, 0x5f, 0xad, 0x3d, 0x15, 0x6c, 0x43, 0xbe, + 0xab, 0x85, 0xf5, 0xbe, 0xa0, 0x12, 0xf4, 0x3d, 0x58, 0x6d, 0x90, 0x3f, 0x8e, 0x8a, 0x10, 0xc0, + 0x2a, 0x80, 0xad, 0xbf, 0x2e, 0xac, 0x8c, 0xbe, 0xe5, 0xe5, 0x67, 0xbf, 0xe6, 0xd8, 0x0f, 0x3f, + 0x4c, 0x61, 0x8a, 0xbf, 0x12, 0x06, 0x37, 0xbf, 0xf1, 0xcd, 0xdc, 0xbf, 0xa9, 0xd9, 0x00, 0xbe, + 0x33, 0x0b, 0x91, 0x3d, 0x1b, 0xb4, 0x44, 0xbd, 0x82, 0xe3, 0xce, 0x3e, 0x1d, 0x55, 0x73, 0xbf, + 0x47, 0x84, 0xfa, 0x3f, 0x7d, 0x18, 0xa6, 0x3f, 0xf1, 0x23, 0x25, 0xbf, 0xce, 0x0b, 0x25, 0xc0, + 0xaf, 0xce, 0x1d, 0xbc, 0x6c, 0x91, 0xdc, 0xbe, 0x96, 0xd2, 0x82, 0x3b, 0x05, 0x89, 0x6d, 0xbf, + 0x4a, 0x1a, 0x14, 0xbf, 0x36, 0xac, 0x22, 0xc0, 0xd1, 0x78, 0x9d, 0xbe, 0xa8, 0x6c, 0xa2, 0xbc, + 0x39, 0x81, 0x2b, 0x3d, 0x52, 0xe5, 0x5d, 0x3f, 0xfa, 0x88, 0x2b, 0xbf, 0x2a, 0xca, 0x61, 0xbf, + 0x1b, 0x6c, 0xd1, 0x3c, 0xd7, 0x99, 0xc3, 0x3e, 0x7a, 0x8c, 0xc2, 0xbe, 0xc3, 0x4c, 0x31, 0xbf, + 0x6c, 0xbc, 0x2f, 0x3f, 0x5c, 0x15, 0x4a, 0xbf, 0xa0, 0xa1, 0x12, 0x3e, 0x43, 0x5b, 0xf1, 0x3e, + 0xbf, 0xc1, 0x4f, 0x3f, 0xf9, 0xdb, 0x04, 0xbf, 0x2a, 0x9b, 0x39, 0xbf, 0xed, 0x24, 0x68, 0xbf, + 0xd0, 0xe2, 0xe2, 0xbe, 0x7a, 0x5f, 0xb4, 0xbf, 0x1a, 0x83, 0xb9, 0xbf, 0xef, 0x0e, 0x3d, 0x3d, + 0x2c, 0x4d, 0x06, 0x3f, 0x75, 0x03, 0xbd, 0xbe, 0x1c, 0x32, 0x28, 0xbf, 0x99, 0x41, 0x94, 0x3f, + 0x5f, 0x3f, 0x0a, 0x40, 0x64, 0x0c, 0x8d, 0xc0, 0x99, 0xdb, 0x5d, 0x3f, 0x49, 0x3c, 0x53, 0x3d, + 0xb9, 0xb2, 0xbf, 0x3f, 0x64, 0x93, 0x58, 0xbf, 0x9d, 0x08, 0x0a, 0xbf, 0x90, 0xc6, 0x18, 0x3f, + 0xeb, 0xa3, 0x98, 0x3e, 0xe9, 0x92, 0x01, 0xbc, 0x68, 0xef, 0xb6, 0xba, 0x43, 0xed, 0x94, 0x3f, + 0x8b, 0xf6, 0x43, 0x3f, 0x3e, 0x13, 0xa5, 0xbe, 0x70, 0x0d, 0x97, 0x3e, 0x83, 0x81, 0x26, 0xbd, + 0x9b, 0x8f, 0xae, 0x3f, 0x03, 0x14, 0x60, 0xbf, 0x16, 0x9d, 0xac, 0xbf, 0x4f, 0xac, 0xc0, 0x3f, + 0xc6, 0x6d, 0x98, 0xbf, 0xe4, 0xe7, 0x26, 0x3f, 0x2d, 0x12, 0x28, 0xbe, 0x53, 0x28, 0x01, 0xbe, + 0x0e, 0x24, 0xae, 0x3f, 0x7c, 0x6e, 0x96, 0x3f, 0x4e, 0xc1, 0xd3, 0xbf, 0x76, 0xb7, 0xc8, 0xbe, + 0xdb, 0x89, 0x02, 0xbf, 0xe6, 0x79, 0xeb, 0x3e, 0x8d, 0xaa, 0x06, 0xbe, 0x15, 0xd4, 0x14, 0xbf, + 0xb7, 0xee, 0xd7, 0x3e, 0x07, 0x02, 0xd8, 0x3f, 0x59, 0x81, 0x03, 0xc0, 0xeb, 0x2c, 0x09, 0xbf, + 0x56, 0x63, 0xcb, 0xbf, 0x56, 0x93, 0x3b, 0x3e, 0x95, 0x5c, 0xed, 0xbe, 0xea, 0x26, 0x75, 0x3f, + 0xb3, 0xdb, 0x96, 0x3e, 0xb4, 0xa9, 0x20, 0x3e, 0x87, 0x35, 0xd5, 0x3f, 0xa0, 0x3b, 0xdc, 0x3e, + 0x10, 0x74, 0xeb, 0x3f, 0xee, 0xbf, 0xac, 0xbf, 0x0f, 0xb3, 0x1c, 0xbf, 0x6b, 0x1a, 0xb9, 0x3f, + 0xe5, 0xbb, 0x0c, 0x40, 0x3d, 0xea, 0xb9, 0x3f, 0xa3, 0xf5, 0x7f, 0x3f, 0x95, 0x6f, 0xc1, 0x3e, + 0x48, 0xdb, 0xa7, 0xbf, 0x7c, 0x10, 0x74, 0xbe, 0x03, 0xbd, 0x77, 0x3f, 0x44, 0x38, 0x0a, 0xbf, + 0x88, 0x40, 0x08, 0x3f, 0x34, 0xac, 0x2a, 0x3f, 0xe7, 0x71, 0x77, 0x3f, 0xf5, 0xa0, 0x22, 0x3e, + 0x73, 0x3c, 0xe0, 0x3f, 0xfd, 0xb0, 0xaa, 0xbe, 0xb1, 0xb0, 0x1f, 0x3f, 0x35, 0xae, 0xae, 0xbf, + 0x46, 0xdc, 0x03, 0x40, 0xeb, 0x54, 0xcd, 0x3e, 0xc1, 0x3b, 0x21, 0xbe, 0xce, 0x67, 0x43, 0xbe, + 0xc5, 0x2b, 0xb2, 0x3f, 0x46, 0x30, 0x53, 0x3f, 0x76, 0x5a, 0x5a, 0xbf, 0x1b, 0x33, 0xa6, 0x3e, + 0x97, 0x19, 0x0c, 0x3f, 0x4d, 0x67, 0x25, 0xbf, 0xae, 0xa5, 0x6c, 0x3f, 0xb1, 0xfe, 0x17, 0x3d, + 0xfc, 0x32, 0x03, 0xbe, 0xbc, 0x9e, 0xa7, 0xbe, 0x7c, 0x69, 0x98, 0x3f, 0xed, 0x41, 0xdb, 0x3e, + 0x81, 0x72, 0x7c, 0xbe, 0xc2, 0x3d, 0x9a, 0xbf, 0xcc, 0x47, 0x26, 0xc0, 0x53, 0xeb, 0x8b, 0x3e, + 0x04, 0x58, 0x8d, 0x3f, 0x7e, 0x73, 0x1e, 0xbe, 0x54, 0x43, 0xc9, 0xbe, 0x29, 0x4d, 0xe5, 0xbf, + 0x9a, 0x4d, 0x52, 0x3d, 0x25, 0xe5, 0x7c, 0x3e, 0x69, 0x23, 0x55, 0xbf, 0x96, 0xc5, 0xfe, 0x3e, + 0xb6, 0x40, 0x6a, 0x3f, 0x3a, 0x36, 0x62, 0x3f, 0x3e, 0x27, 0x8c, 0x3e, 0x07, 0xd0, 0x36, 0x3f, + 0x4f, 0x34, 0x1c, 0x3f, 0x87, 0x2d, 0x01, 0x3f, 0x98, 0xf4, 0xe1, 0xbe, 0x40, 0x21, 0xae, 0x3f, + 0x5c, 0x6e, 0xa9, 0xbe, 0x88, 0x09, 0x05, 0xbf, 0x8c, 0x9a, 0x1c, 0x3f, 0x4f, 0xba, 0x86, 0xbe, + 0x95, 0x1a, 0xf0, 0xbf, 0x80, 0x85, 0x96, 0xbf, 0xcf, 0xd5, 0x3d, 0x3f, 0x61, 0x23, 0xb8, 0x3e, + 0x0d, 0x12, 0x0b, 0xbf, 0x80, 0x08, 0x83, 0xbf, 0xc8, 0x8a, 0x0e, 0xbe, 0x9e, 0x2c, 0xc8, 0xbe, + 0xf1, 0xce, 0xef, 0xbf, 0x74, 0x62, 0x9f, 0xbe, 0x74, 0x23, 0x80, 0xbe, 0x00, 0xd1, 0x84, 0x3f, + 0x45, 0xff, 0x60, 0x3f, 0x4b, 0x78, 0x17, 0xbf, 0x47, 0xdd, 0xa6, 0xbf, 0xf5, 0xec, 0x17, 0x3f, + 0xf6, 0x66, 0xa5, 0x3f, 0x40, 0x8e, 0x4e, 0xbf, 0xab, 0x71, 0x28, 0x3e, 0x0c, 0xad, 0xb5, 0xbe, + 0xd6, 0x5c, 0x59, 0xbf, 0x71, 0x1c, 0x21, 0x3f, 0x80, 0x7e, 0x0d, 0x40, 0x5e, 0x1d, 0x23, 0x3e, + 0x8f, 0x0d, 0x45, 0xbf, 0x16, 0xb6, 0x3c, 0xc0, 0x74, 0xb7, 0x96, 0xbf, 0xdc, 0xa4, 0xc2, 0xbf, + 0xd2, 0x3e, 0xca, 0xbf, 0xf3, 0x38, 0x0b, 0xbf, 0x00, 0x07, 0x7a, 0x3f, 0x43, 0x9c, 0x2c, 0x3f, + 0x5f, 0xaa, 0xcf, 0xbf, 0x90, 0x8a, 0x45, 0xbf, 0x1d, 0xd2, 0x83, 0xbf, 0x23, 0xf3, 0x30, 0xbd, + 0x33, 0xa1, 0xf3, 0xbf, 0xc8, 0x41, 0x93, 0xbe, 0x3c, 0x1a, 0x65, 0xbe, 0xfd, 0xda, 0xed, 0xbe, + 0x26, 0x3d, 0xd3, 0xbe, 0xcd, 0xb0, 0x0f, 0xc0, 0x74, 0x92, 0x19, 0x3f, 0x00, 0x4d, 0x6f, 0x3f, + 0xa0, 0x47, 0xa9, 0x3e, 0x38, 0x05, 0xdf, 0xbf, 0x41, 0x4e, 0xc3, 0xbe, 0x52, 0xc2, 0x1e, 0xbe, + 0xc9, 0xb3, 0xe6, 0x3e, 0x03, 0xbe, 0x1e, 0x3f, 0x9f, 0xaf, 0x85, 0xbf, 0xbb, 0xbc, 0x9c, 0x3f, + 0xe1, 0xfc, 0x16, 0xbf, 0xea, 0x09, 0x3e, 0xbe, 0xbb, 0xe0, 0x42, 0x40, 0xd2, 0x28, 0xd4, 0x3e, + 0x7b, 0xd1, 0x73, 0xbf, 0xd3, 0x77, 0x98, 0x3f, 0x73, 0x4c, 0x5e, 0xbf, 0x2c, 0x3e, 0x11, 0x3f, + 0x95, 0x64, 0x15, 0xbe, 0x0d, 0x4f, 0x1a, 0x3f, 0x7f, 0x1b, 0xc8, 0x3e, 0x1d, 0x68, 0x35, 0x3f, + 0x99, 0xf7, 0xd6, 0xbe, 0x3d, 0xb9, 0x99, 0x3f, 0x17, 0x50, 0xce, 0x3e, 0x8e, 0x04, 0x8d, 0xbe, + 0x08, 0x0c, 0xf9, 0x3f, 0x6b, 0xb2, 0xd0, 0xbe, 0xc7, 0xcb, 0xba, 0xbe, 0xd0, 0x70, 0x3a, 0x3e, + 0xa9, 0x54, 0xe8, 0x3e, 0xe7, 0x3b, 0xc4, 0xbe, 0x94, 0x5b, 0x5c, 0x3f, 0x57, 0xc4, 0xfc, 0xbd, + 0x38, 0x6f, 0x9b, 0xbd, 0xdb, 0x1d, 0x47, 0x3f, 0x36, 0x78, 0x78, 0x3f, 0x9f, 0x61, 0x52, 0xbf, + 0x67, 0x23, 0x86, 0x3e, 0x74, 0x04, 0xde, 0xbe, 0x19, 0x1b, 0x51, 0xbf, 0x73, 0x5f, 0x05, 0x3e, + 0x06, 0xe6, 0x9c, 0x3e, 0x95, 0xfe, 0x9b, 0x3f, 0x94, 0xce, 0x76, 0xbf, 0xc1, 0xf8, 0x8e, 0x3f, + 0x8c, 0x5b, 0x63, 0x3f, 0x70, 0x00, 0xaa, 0xbf, 0x1a, 0xb8, 0x6c, 0xbf, 0x42, 0x20, 0x91, 0x3d, + 0x97, 0x4b, 0x1a, 0xbf, 0xbc, 0x32, 0xb4, 0x3e, 0x77, 0xf0, 0xc6, 0x3e, 0xeb, 0x56, 0xa2, 0x3f, + 0x0e, 0xb0, 0x25, 0x40, 0x4b, 0xce, 0x40, 0xbf, 0x5b, 0xfd, 0x35, 0xbf, 0x9e, 0x78, 0x7f, 0xbe, + 0xe3, 0x03, 0xac, 0xbf, 0x89, 0xc2, 0x77, 0x3f, 0xd8, 0x2e, 0x63, 0xbf, 0xce, 0x9f, 0x40, 0x3f, + 0xe2, 0x52, 0xce, 0x3e, 0x5c, 0xeb, 0x63, 0x3f, 0x4e, 0xd3, 0x9d, 0x3f, 0x7c, 0xe3, 0x47, 0xbf, + 0xea, 0xca, 0x31, 0xbf, 0xae, 0x7b, 0x0d, 0x3f, 0x04, 0xa0, 0x58, 0x3f, 0x8a, 0xc5, 0x87, 0x3f, + 0x22, 0xfa, 0xa8, 0xbf, 0x5e, 0x7e, 0xbf, 0xbd, 0xdc, 0x05, 0x70, 0x3f, 0x8e, 0x2c, 0xee, 0x3e, + 0xfb, 0x13, 0x14, 0xbf, 0x2e, 0xf2, 0x17, 0x3d, 0x7f, 0x3e, 0xe8, 0x3c, 0x86, 0xfa, 0x35, 0xbf, + 0x21, 0x83, 0x8d, 0x3e, 0x77, 0xab, 0x3b, 0xbf, 0xda, 0x43, 0x00, 0xbf, 0x32, 0xd5, 0x7e, 0xbd, + 0x5a, 0xd6, 0xa1, 0xbf, 0xc3, 0xad, 0xdd, 0xbe, 0x33, 0xa0, 0x20, 0x3f, 0x07, 0x4a, 0x0e, 0x3f, + 0x4c, 0x98, 0x5d, 0x3e, 0x0e, 0xba, 0x86, 0x3f, 0xe4, 0xc3, 0x42, 0xbc, 0x42, 0x8f, 0x04, 0x3f, + 0x49, 0xc0, 0x68, 0xbe, 0xe9, 0x21, 0x18, 0x40, 0xd0, 0x13, 0x85, 0x3e, 0x65, 0xc6, 0x8c, 0xbd, + 0xa4, 0x15, 0xff, 0x3e, 0xf5, 0x61, 0x79, 0xbd, 0x44, 0xbb, 0x3e, 0x3f, 0xc5, 0xdd, 0xa5, 0xbe, + 0xc7, 0x8d, 0xea, 0xbf, 0x31, 0xf2, 0xce, 0x3f, 0x7e, 0xb7, 0x5d, 0x3f, 0xfa, 0x62, 0x8a, 0xbe, + 0x98, 0x4a, 0x82, 0xbe, 0x3a, 0x08, 0x29, 0x40, 0xb1, 0xc8, 0xec, 0x3f, 0x60, 0x74, 0x82, 0x3f, + 0x35, 0x65, 0x1c, 0x3f, 0x9b, 0x63, 0x75, 0x3d, 0xe5, 0x3c, 0x21, 0x3f, 0xf8, 0xac, 0x84, 0x3f, + 0xc5, 0xe6, 0x9d, 0xbf, 0x2a, 0xf6, 0xc5, 0x3e, 0x34, 0x33, 0x6b, 0xbf, 0x66, 0x93, 0x71, 0xbd, + 0x4b, 0xff, 0xbe, 0xbf, 0x8f, 0x72, 0x05, 0xbf, 0x4e, 0xee, 0xc7, 0xbc, 0x20, 0x1a, 0xa1, 0x3e, + 0xec, 0x65, 0x9c, 0xbf, 0x94, 0x44, 0x4a, 0xbe, 0x6f, 0x68, 0x20, 0x3e, 0xd7, 0x49, 0x04, 0x40, + 0x53, 0x37, 0x30, 0xbf, 0x92, 0x86, 0x1c, 0xbe, 0x20, 0x0c, 0xd9, 0x3f, 0xfe, 0xa7, 0x98, 0x3f, + 0x92, 0xa3, 0x72, 0x3f, 0xed, 0x1c, 0xce, 0x3d, 0x41, 0xb5, 0x94, 0xbe, 0xae, 0x1c, 0xa7, 0x3e, + 0x9d, 0xdc, 0x9b, 0xbf, 0xe7, 0x82, 0x23, 0x40, 0xe6, 0x19, 0x28, 0xbf, 0xb9, 0xfb, 0x94, 0xbf, + 0xb1, 0x45, 0xa2, 0xbe, 0x79, 0x6e, 0x9c, 0xbe, 0xc6, 0x56, 0x6d, 0x3f, 0xa4, 0x5a, 0x02, 0x40, + 0x10, 0x10, 0x41, 0xbd, 0xbd, 0x92, 0xbf, 0xbe, 0xa7, 0x20, 0x63, 0x3f, 0x15, 0x39, 0x83, 0xbf, + 0x53, 0x34, 0x2b, 0xbe, 0x96, 0x72, 0xa4, 0x3f, 0x47, 0x91, 0xfe, 0xbf, 0x36, 0xea, 0xcd, 0xbe, + 0x8e, 0x28, 0x91, 0xbe, 0x89, 0x45, 0x9e, 0x3e, 0xa6, 0x56, 0x18, 0x3c, 0x4c, 0x2c, 0x5d, 0x3e, + 0x13, 0xbd, 0x3b, 0xbf, 0x10, 0xcb, 0xcc, 0xbf, 0x33, 0x58, 0x9f, 0xbf, 0x2d, 0x85, 0x29, 0x3f, + 0xfe, 0x70, 0x85, 0xbf, 0x67, 0x91, 0x09, 0x3f, 0xf4, 0xda, 0x28, 0xbe, 0xa3, 0x72, 0x85, 0xbf, + 0x2c, 0x0d, 0xce, 0x3e, 0x49, 0xc4, 0x34, 0xbf, 0xb8, 0x18, 0x80, 0xbe, 0x63, 0x92, 0xc8, 0x3e, + 0x59, 0x84, 0xb9, 0x3f, 0x30, 0xb0, 0x94, 0x3f, 0x5b, 0xaa, 0xf2, 0xbe, 0x00, 0x52, 0x32, 0xbf, + 0x2c, 0x14, 0x8b, 0x3f, 0xf2, 0x65, 0xa4, 0xbf, 0x72, 0x30, 0xec, 0xbd, 0xaf, 0xb0, 0x9d, 0xbe, + 0x9b, 0xdc, 0x93, 0xbf, 0x3b, 0x8c, 0x1d, 0xbe, 0x22, 0x50, 0x39, 0x3e, 0x2c, 0xdf, 0x80, 0xbf, + 0x0a, 0x89, 0x18, 0xbf, 0xe8, 0x84, 0xb1, 0xbf, 0x36, 0x36, 0x7a, 0x3f, 0xe2, 0xdb, 0x28, 0x40, + 0x99, 0x1b, 0x01, 0xc0, 0x23, 0x56, 0x1d, 0xbf, 0x9f, 0xf0, 0x41, 0x3f, 0x50, 0x0c, 0x44, 0x3f, + 0x6a, 0x7b, 0x02, 0xbf, 0xd9, 0xdf, 0xe6, 0x3f, 0xca, 0xac, 0xe9, 0xbe, 0x32, 0x20, 0x19, 0xbf, + 0x74, 0x1a, 0xa5, 0xbf, 0xf8, 0xf1, 0x24, 0x3f, 0xfd, 0x45, 0x00, 0x3f, 0xca, 0x6f, 0x80, 0xbe, + 0x1f, 0x86, 0x5c, 0x3e, 0xc6, 0x34, 0x41, 0x3f, 0xeb, 0x0b, 0xd7, 0xbd, 0x9c, 0x6c, 0x90, 0x3e, + 0x2b, 0x87, 0xcb, 0x3e, 0x7a, 0xbc, 0x57, 0x3f, 0x36, 0x6f, 0x1e, 0xbe, 0x12, 0xbd, 0x6d, 0x3e, + 0x7e, 0x8f, 0xbc, 0x3e, 0x82, 0x91, 0xaf, 0xbe, 0x61, 0x72, 0x3b, 0x3f, 0xfa, 0x54, 0x7d, 0x3f, + 0x5a, 0x38, 0x81, 0x3f, 0x09, 0x04, 0xf7, 0x3e, 0xc1, 0x7b, 0xa0, 0xbf, 0xd1, 0x5c, 0x81, 0x3e, + 0x48, 0x6e, 0x3f, 0x3e, 0x42, 0x28, 0x03, 0x3f, 0x3f, 0x22, 0xc8, 0xbf, 0x11, 0x34, 0xf2, 0xbe, + 0xff, 0xa4, 0x0a, 0xbf, 0x34, 0xe0, 0x1f, 0xbe, 0xcb, 0x44, 0x04, 0x40, 0x07, 0x7b, 0x05, 0x3f, + 0xa1, 0x37, 0x85, 0xbe, 0x72, 0x32, 0x2f, 0x3f, 0xf0, 0x9b, 0x77, 0x3e, 0x09, 0xef, 0xac, 0x3d, + 0x6d, 0xc4, 0x60, 0xbe, 0xc3, 0xa4, 0x63, 0xbf, 0x15, 0xa8, 0x94, 0xbe, 0x12, 0xe4, 0x2a, 0x40, + 0x48, 0xc3, 0x51, 0x3f, 0x5e, 0x42, 0x86, 0x3f, 0x4b, 0x5e, 0x2d, 0x3f, 0x95, 0x04, 0x83, 0xbe, + 0xbe, 0x31, 0x07, 0x40, 0xed, 0xcb, 0xbd, 0xbe, 0x63, 0xa7, 0x36, 0x3e, 0xf9, 0xa5, 0x2b, 0x3f, + 0x12, 0xbd, 0x6d, 0x3f, 0x66, 0xa4, 0xcb, 0x3f, 0x3e, 0xd0, 0xc5, 0x3f, 0x32, 0xeb, 0xdc, 0x3f, + 0x8c, 0x0d, 0x99, 0xbe, 0xd3, 0x07, 0x96, 0x3f, 0x64, 0xc0, 0xee, 0x3f, 0xbe, 0x0b, 0xcb, 0x3f, + 0x64, 0x45, 0xc5, 0x3c, 0xcc, 0x2d, 0x84, 0xbf, 0xa3, 0xcf, 0x34, 0xbf, 0xa3, 0xce, 0x32, 0xbe, + 0xc6, 0x11, 0xa5, 0xbe, 0xf0, 0xb5, 0x42, 0x3f, 0x18, 0xd5, 0xe9, 0x3e, 0x30, 0x23, 0xd4, 0x3e, + 0xe8, 0x81, 0x0b, 0xc0, 0x20, 0x1a, 0x91, 0xbe, 0xcf, 0x6c, 0xbd, 0x3f, 0x33, 0x54, 0xf3, 0x3d, + 0xce, 0xf8, 0xa4, 0x3f, 0xc4, 0x15, 0x9e, 0xbd, 0x10, 0x5a, 0x43, 0x3e, 0x73, 0x5f, 0x5c, 0x3d, + 0x1c, 0xb9, 0x20, 0xbf, 0x00, 0xdb, 0x30, 0x3f, 0xeb, 0x76, 0x13, 0x3d, 0x6e, 0x88, 0x5c, 0xbf, + 0xc9, 0xf0, 0x8b, 0xbd, 0xb0, 0x89, 0xc4, 0x3e, 0x94, 0xcc, 0x55, 0xbe, 0x9c, 0xfb, 0x4c, 0x3f, + 0x9f, 0xb2, 0xf4, 0xbf, 0x98, 0xef, 0xf9, 0x3e, 0x4e, 0x62, 0x28, 0x3f, 0x0d, 0x53, 0x31, 0xbf, + 0x53, 0x48, 0x76, 0xbf, 0x27, 0x4f, 0xce, 0xbd, 0x38, 0x36, 0xac, 0x3f, 0xe0, 0xcf, 0x49, 0x3f, + 0x9c, 0xa2, 0x80, 0xbf, 0x0d, 0x87, 0xf0, 0x3d, 0x98, 0xee, 0xce, 0x3f, 0x74, 0x70, 0x26, 0xbf, + 0x9b, 0x52, 0x84, 0xbf, 0x72, 0x8f, 0xe4, 0xbe, 0x0a, 0x5f, 0x54, 0xbe, 0x20, 0xe8, 0xb4, 0x3f, + 0x5f, 0x57, 0xd2, 0xbf, 0xff, 0xf7, 0x12, 0x3f, 0xd2, 0x28, 0x99, 0xbf, 0xf0, 0x4a, 0x4f, 0x3e, + 0x9d, 0x98, 0xec, 0xbf, 0x98, 0x1d, 0xb4, 0xbf, 0x65, 0xd7, 0x2a, 0x3d, 0x09, 0x9b, 0x93, 0x3f, + 0x36, 0xd8, 0x1b, 0xbf, 0xcb, 0x5a, 0xbe, 0xbe, 0x63, 0x99, 0x3e, 0xbf, 0x59, 0x44, 0xec, 0xbd, + 0xc2, 0x30, 0x1d, 0xbf, 0x83, 0xcf, 0xeb, 0x3e, 0x93, 0x49, 0xe2, 0xbe, 0xbe, 0x26, 0x3a, 0xbf, + 0xc1, 0x9e, 0xf9, 0xbf, 0xbb, 0x1b, 0x58, 0xbf, 0xaa, 0xba, 0x2c, 0xbe, 0x71, 0x66, 0xaf, 0xbf, + 0x5f, 0x4f, 0x52, 0x3e, 0xe2, 0x1f, 0x5c, 0x3f, 0x4c, 0xd4, 0x6a, 0x3e, 0x12, 0xc7, 0xee, 0x3d, + 0x37, 0x50, 0x18, 0x3d, 0xa3, 0x31, 0xd1, 0xbd, 0xd6, 0xda, 0x74, 0xbe, 0x79, 0xbc, 0xa1, 0x3f, + 0x97, 0xbc, 0x0a, 0xbf, 0xc6, 0x5b, 0x41, 0x3f, 0xbb, 0x04, 0xcf, 0xbf, 0xc5, 0x18, 0x43, 0xbf, + 0xfb, 0x76, 0xe5, 0x3f, 0x67, 0x2e, 0x86, 0x3d, 0xc7, 0xec, 0x6d, 0xbf, 0xf1, 0xb7, 0xac, 0x3f, + 0x57, 0x11, 0x3e, 0x3f, 0xdf, 0xa7, 0x7f, 0x3e, 0x77, 0x61, 0x3e, 0xbf, 0x79, 0xec, 0xfe, 0x3f, + 0xf7, 0x27, 0xe7, 0x3e, 0x1a, 0xc5, 0xa5, 0xbe, 0xec, 0xf9, 0xf7, 0x3e, 0x8f, 0x6b, 0xd0, 0xbe, + 0xfe, 0x31, 0xe4, 0xbd, 0x4c, 0x97, 0x85, 0xbe, 0xcf, 0x85, 0x46, 0xbe, 0x2f, 0x0b, 0x99, 0x3f, + 0x66, 0x7b, 0x29, 0xbd, 0xb9, 0xff, 0xff, 0xbe, 0xef, 0x41, 0x25, 0x3f, 0xe5, 0x50, 0xf7, 0x3e, + 0xe0, 0xe9, 0xa2, 0xbe, 0xaa, 0x40, 0x37, 0xbf, 0x85, 0x73, 0xe4, 0x3e, 0x28, 0xdc, 0x9d, 0xbe, + 0x53, 0xec, 0xd4, 0x3e, 0x63, 0xa7, 0x36, 0x3f, 0xcb, 0xe3, 0x09, 0x3f, 0x6a, 0x54, 0xc7, 0xbd, + 0x96, 0x45, 0xf4, 0x3f, 0x02, 0xa9, 0x07, 0xbd, 0x7c, 0x2e, 0x3f, 0xbf, 0x04, 0x19, 0x7c, 0xbf, + 0xf8, 0x36, 0x61, 0x3e, 0x25, 0xef, 0xc3, 0xbf, 0x0e, 0xd7, 0x98, 0x3f, 0x16, 0xae, 0x51, 0x3f, + 0xff, 0xd4, 0xea, 0xbe, 0x02, 0x5d, 0x0c, 0xbf, 0x8d, 0x5e, 0xf8, 0xbe, 0x2d, 0x66, 0xb1, 0xbd, + 0x2e, 0xd4, 0x51, 0x3f, 0xe0, 0x1a, 0x93, 0xbe, 0x95, 0x96, 0xcb, 0x3f, 0x99, 0xa0, 0xab, 0xbf, + 0x87, 0x75, 0x0d, 0x3f, 0x90, 0xf4, 0xbd, 0xbf, 0xd7, 0x1e, 0x26, 0x40, 0x5d, 0xc9, 0x83, 0x3f, + 0x5b, 0x1b, 0x17, 0x3f, 0xd4, 0xe6, 0x07, 0xc0, 0xae, 0x09, 0xcb, 0x3e, 0x83, 0xa9, 0x97, 0x3d, + 0x9d, 0xf4, 0xbf, 0x3f, 0x01, 0xe5, 0xb3, 0x3d, 0xf2, 0x3a, 0x9a, 0x3e, 0x65, 0x1c, 0x0c, 0xbf, + 0xad, 0x91, 0x6a, 0xbe, 0x7a, 0x8b, 0x0f, 0x3f, 0xfe, 0x20, 0x2a, 0x3d, 0xae, 0xbe, 0x09, 0x40, + 0xed, 0xfe, 0xa4, 0x3f, 0xa3, 0xfe, 0x21, 0xbf, 0xba, 0x12, 0x22, 0xbe, 0xc0, 0xf7, 0xcb, 0xbe, + 0xdf, 0x81, 0xa1, 0x3d, 0x2a, 0x80, 0x27, 0x3f, 0xb0, 0xa6, 0x03, 0x3f, 0x9f, 0xb1, 0xe4, 0x3f, + 0x00, 0xee, 0x8a, 0xbe, 0xbc, 0x85, 0x18, 0xbf, 0xf5, 0x8c, 0x65, 0x3e, 0x69, 0xaf, 0xb3, 0xbd, + 0x01, 0xba, 0x20, 0xc0, 0x67, 0x8c, 0x53, 0x3f, 0xc7, 0x91, 0xe9, 0x3e, 0x82, 0x1e, 0x66, 0xbe, + 0xfa, 0xed, 0x1b, 0x3f, 0xde, 0x84, 0x04, 0xbf, 0xce, 0x2b, 0xa8, 0x3f, 0x8f, 0xfd, 0x34, 0xbf, + 0x61, 0x17, 0x53, 0xbe, 0x7f, 0xc1, 0xf1, 0x3e, 0x84, 0x66, 0x63, 0xbd, 0x40, 0xf4, 0x95, 0x3e, + 0x2b, 0x75, 0x2f, 0x3f, 0x7a, 0x89, 0x17, 0xbf, 0x21, 0x51, 0x94, 0xbf, 0xbb, 0x9b, 0xc0, 0x3f, + 0x2d, 0xce, 0xa4, 0x3f, 0x8c, 0x30, 0xdc, 0x3e, 0x92, 0xca, 0x0e, 0x3e, 0x26, 0x66, 0x2a, 0xbf, + 0xb3, 0x26, 0xdc, 0x3d, 0xd0, 0xcd, 0xa2, 0x3f, 0x47, 0x8d, 0x2b, 0xbe, 0xbf, 0xa4, 0x10, 0xbf, + 0x23, 0x07, 0x71, 0x3e, 0xc2, 0xa6, 0xc5, 0xbf, 0x80, 0x4f, 0xb1, 0xbf, 0x74, 0xe1, 0xc5, 0x3e, + 0xae, 0xb7, 0x0b, 0x3f, 0xdf, 0xbd, 0xab, 0x3f, 0x5f, 0xd1, 0x63, 0x3e, 0xa6, 0x82, 0x00, 0x3f, + 0xe4, 0xa4, 0x27, 0xbe, 0xc2, 0x41, 0x01, 0xbf, 0xdb, 0xf7, 0x53, 0x3e, 0x08, 0x77, 0x4f, 0xbe, + 0x7c, 0x5a, 0x57, 0xbf, 0x78, 0x96, 0x02, 0x3d, 0xd8, 0x7f, 0x90, 0xbf, 0x9c, 0xec, 0x29, 0xbd, + 0xb2, 0x61, 0xa7, 0x3f, 0x9c, 0xca, 0xb0, 0x3f, 0x5a, 0x17, 0xc2, 0x3f, 0x4b, 0x84, 0xcd, 0xbe, + 0x61, 0x0e, 0xc7, 0x3e, 0xfe, 0xdc, 0x27, 0xbf, 0x6f, 0xba, 0x80, 0x3e, 0x0b, 0x12, 0xb5, 0xbd, + 0x72, 0xb3, 0xc9, 0x3d, 0xa5, 0xd9, 0x66, 0x3f, 0x03, 0x27, 0x14, 0x3f, 0x1c, 0x5c, 0xac, 0x3e, + 0xf1, 0xaf, 0xa8, 0x3f, 0xf5, 0x8a, 0x5e, 0x3e, 0x21, 0x7a, 0xcb, 0x3e, 0x6a, 0x1b, 0x3a, 0xbf, + 0x61, 0x1a, 0x36, 0x3e, 0x47, 0x18, 0xf4, 0xbe, 0xfb, 0x44, 0xeb, 0x3f, 0xed, 0xec, 0x84, 0xbf, + 0xa9, 0xba, 0x2f, 0xbf, 0x57, 0x9b, 0xd4, 0x3e, 0xb8, 0xed, 0xde, 0x3f, 0xc2, 0x0f, 0x15, 0x3e, + 0xb8, 0x75, 0x43, 0xbf, 0x98, 0x16, 0x0e, 0xbd, 0x92, 0x44, 0x84, 0x3e, 0x6e, 0x4c, 0xe5, 0x3f, + 0x36, 0x90, 0x6f, 0xbd, 0x49, 0x20, 0x0a, 0xbf, 0x56, 0x7d, 0x0a, 0x40, 0x4d, 0xc7, 0xad, 0x3f, + 0x7f, 0x1a, 0x89, 0xbe, 0xc0, 0x51, 0xe7, 0x3f, 0xdf, 0x12, 0x74, 0x3e, 0x33, 0x0e, 0x8d, 0xbf, + 0x3b, 0xf9, 0x50, 0xbf, 0x5a, 0x90, 0x95, 0xbf, 0x8e, 0x4d, 0x14, 0xbf, 0x7b, 0x43, 0x4f, 0xbf, + 0x81, 0xee, 0x56, 0x3f, 0xa8, 0x23, 0x13, 0xbe, 0x40, 0xe0, 0x80, 0x3f, 0x40, 0x42, 0xe2, 0xbf, + 0x58, 0x4f, 0x39, 0x3f, 0xc3, 0x30, 0x46, 0x3e, 0x2d, 0x04, 0xc6, 0xbf, 0xd3, 0x04, 0x0b, 0xbf, + 0x0f, 0xa8, 0xfd, 0x3f, 0x8b, 0xc7, 0xa8, 0x3f, 0xb4, 0x24, 0xe2, 0x3e, 0x51, 0x9e, 0x54, 0xbe, + 0xd1, 0x8d, 0x6e, 0xbe, 0xf8, 0x1b, 0x15, 0x3e, 0xb7, 0xaf, 0x17, 0x3f, 0xf1, 0x2f, 0xda, 0x3f, + 0x92, 0xc8, 0x17, 0x3f, 0xee, 0x0b, 0x6c, 0xbf, 0xd3, 0x35, 0x69, 0xbf, 0x48, 0x69, 0x1e, 0x3f, + 0x2a, 0x98, 0xb1, 0x3e, 0x9e, 0xab, 0x83, 0xbe, 0x47, 0x71, 0x8d, 0xbf, 0x2f, 0x13, 0x59, 0x3f, + 0x31, 0xed, 0xc8, 0x3e, 0x25, 0x9b, 0xc3, 0xbe, 0x82, 0xe8, 0x3c, 0xbf, 0x5e, 0xf0, 0x04, 0x3e, + 0x81, 0x07, 0xaa, 0xbf, 0x23, 0xe6, 0x87, 0xbf, 0x85, 0x1e, 0x92, 0xbe, 0xf1, 0xfb, 0xaf, 0xbd, + 0xb0, 0xb0, 0x2d, 0x3f, 0xc9, 0xd5, 0x25, 0x3f, 0x7b, 0xe9, 0x06, 0x3e, 0xb3, 0xf0, 0xc5, 0xbe, + 0x2a, 0xcf, 0x57, 0x3e, 0xeb, 0x4d, 0x87, 0x3e, 0xaa, 0x3a, 0x89, 0x3f, 0x5f, 0x35, 0xd8, 0x3e, + 0x5a, 0xd9, 0xc6, 0xbe, 0xb7, 0xe4, 0x12, 0xbf, 0x95, 0x20, 0x65, 0x3f, 0x8a, 0x2f, 0xa8, 0xbd, + 0x09, 0x11, 0xc8, 0xbf, 0x93, 0xf5, 0x80, 0x3f, 0x78, 0x3a, 0x1f, 0x3f, 0x3a, 0x9d, 0x0e, 0xbf, + 0x25, 0x38, 0x67, 0x3f, 0x0d, 0xbe, 0x74, 0x3f, 0x84, 0x08, 0x11, 0xbd, 0xae, 0xae, 0xa4, 0xbf, + 0xd6, 0xe0, 0x9b, 0x3f, 0x64, 0x85, 0x26, 0x3f, 0xd0, 0x7b, 0x82, 0x3f, 0xa3, 0xc7, 0x62, 0x3f, + 0x54, 0xdd, 0xf6, 0x3e, 0x9b, 0xe5, 0x6f, 0xbf, 0x35, 0xa9, 0x9d, 0xbf, 0x3e, 0x21, 0xa1, 0xbf, + 0x56, 0x58, 0x8a, 0xbf, 0x52, 0x54, 0x14, 0x3f, 0x36, 0xcb, 0x64, 0xbf, 0x78, 0xac, 0x58, 0x3f, + 0x63, 0x7e, 0x5e, 0x3f, 0x23, 0xc9, 0x91, 0x3f, 0x41, 0x95, 0xb0, 0x3f, 0x99, 0xa2, 0x30, 0x3f, + 0x9d, 0xf4, 0x27, 0xbf, 0x3e, 0xe1, 0xaf, 0x3e, 0x39, 0x54, 0xad, 0xbf, 0xe0, 0x5c, 0xf8, 0xbe, + 0x36, 0x19, 0x8a, 0x3f, 0x0f, 0x5b, 0x68, 0xbe, 0x51, 0xdf, 0x98, 0x3f, 0x1a, 0xf8, 0x06, 0xbf, + 0xf6, 0xc1, 0x16, 0x3f, 0x30, 0x2e, 0x3e, 0xbf, 0x38, 0xe0, 0xaf, 0x3e, 0x0d, 0xf9, 0x61, 0x3f, + 0xdd, 0xbb, 0x68, 0x3e, 0x3e, 0x61, 0xc4, 0x3d, 0x25, 0x7a, 0x15, 0x3e, 0xce, 0xb5, 0x1c, 0x3e, + 0x49, 0x88, 0x09, 0x3f, 0x86, 0x5b, 0xf9, 0x3f, 0xcb, 0xed, 0x96, 0xbd, 0xcb, 0xd9, 0x3f, 0x3f, + 0x84, 0x9f, 0x0f, 0x3f, 0x5d, 0x0a, 0xa1, 0xbd, 0x30, 0xb1, 0xa6, 0xbf, 0xb1, 0x23, 0x20, 0x3e, + 0x4b, 0xbb, 0xcc, 0x3e, 0xdf, 0x65, 0xfa, 0x3f, 0x5a, 0xb8, 0x32, 0xbf, 0x55, 0x4a, 0xc6, 0xbd, + 0x3d, 0x14, 0x7e, 0xbf, 0xc9, 0x6a, 0x41, 0x3e, 0x1a, 0x7b, 0xc8, 0x3e, 0xd4, 0x52, 0x1b, 0x3e, + 0x81, 0xcb, 0x8c, 0xbd, 0xc4, 0xae, 0xba, 0x3f, 0xca, 0xba, 0x95, 0x3f, 0x71, 0xbd, 0x4b, 0xbf, + 0x08, 0x26, 0xe5, 0x3e, 0xed, 0xad, 0x1a, 0xbf, 0xcd, 0x2c, 0x09, 0x3f, 0xfd, 0x48, 0x3e, 0x3f, + 0x14, 0x76, 0x5a, 0x3f, 0x31, 0x8d, 0x7a, 0x3f, 0xae, 0xba, 0x0f, 0x3e, 0x11, 0x27, 0xa4, 0x3f, + 0xd9, 0xae, 0x9b, 0xbe, 0x45, 0x9b, 0xcc, 0x3f, 0x63, 0x00, 0xbd, 0xbf, 0x3f, 0x81, 0x59, 0xbf, + 0x66, 0xcc, 0x1a, 0xbf, 0x25, 0x25, 0xab, 0xbf, 0x6a, 0x64, 0x91, 0x3f, 0xb2, 0xed, 0x92, 0x3f, + 0x7b, 0xf2, 0x30, 0xbd, 0x0f, 0x53, 0x30, 0xbd, 0x1c, 0x73, 0x04, 0xbf, 0x69, 0xae, 0x91, 0x3f, + 0x24, 0x91, 0x2e, 0x3f, 0x2a, 0x51, 0xdd, 0x3f, 0xc8, 0xf0, 0xa1, 0xbf, 0xe6, 0x5e, 0x23, 0xbe, + 0x1f, 0x74, 0x3e, 0xbf, 0x36, 0x5c, 0x66, 0x3f, 0xe9, 0xb1, 0xdf, 0xbe, 0x03, 0x80, 0x90, 0x3f, + 0x62, 0x31, 0x8a, 0xbf, 0x04, 0x89, 0x0b, 0x3f, 0xff, 0xc5, 0x76, 0x3f, 0x6e, 0xf7, 0x96, 0xbf, + 0x6c, 0xda, 0x9b, 0xbe, 0x7b, 0xde, 0x89, 0x3e, 0x74, 0x7d, 0x61, 0xbe, 0x66, 0xf3, 0xe1, 0x3f, + 0xcf, 0xd5, 0x82, 0xbf, 0x6d, 0xa7, 0x9c, 0x3f, 0x6d, 0x3b, 0xf2, 0xbe, 0xc7, 0x15, 0xa8, 0xbf, + 0xa1, 0x9a, 0xa8, 0x3f, 0xb9, 0xa3, 0x1a, 0x3f, 0x6d, 0x80, 0x2e, 0x3f, 0x4b, 0xe3, 0xc0, 0xbe, + 0x14, 0xba, 0x91, 0x3f, 0x88, 0x11, 0xed, 0xbc, 0xb2, 0xe1, 0xc1, 0xbe, 0x40, 0x18, 0x17, 0xbf, + 0x3c, 0x5e, 0xbb, 0x3c, 0x06, 0x97, 0x23, 0x40, 0xe4, 0x06, 0xb9, 0xbf, 0x57, 0xf1, 0x1a, 0xbe, + 0x49, 0x85, 0xa8, 0x3c, 0xd7, 0xfa, 0x62, 0x3d, 0x63, 0x9d, 0x96, 0xbe, 0x64, 0x02, 0x23, 0x3e, + 0x9a, 0x9d, 0x15, 0x3c, 0xeb, 0xbb, 0x6a, 0xbf, 0xfb, 0xd8, 0xa7, 0x3f, 0x2f, 0x3e, 0xc7, 0xbe, + 0xe8, 0x3b, 0xeb, 0xbe, 0x90, 0x12, 0x75, 0x3d, 0xd0, 0x35, 0x94, 0x3d, 0x04, 0x0e, 0x4b, 0xbf, + 0x20, 0xff, 0xc2, 0x3e, 0x98, 0xb2, 0x4a, 0xbf, 0x9f, 0x8d, 0x2b, 0x3f, 0x7c, 0x8e, 0xcb, 0x3e, + 0x9d, 0xbc, 0x80, 0x3e, 0x59, 0xa0, 0x4b, 0x3f, 0x52, 0x95, 0x13, 0xbf, 0xe4, 0x5e, 0x50, 0xbe, + 0x9b, 0x5e, 0xb7, 0x3f, 0x6d, 0xa0, 0xa8, 0x3f, 0x82, 0xc6, 0x1b, 0xbe, 0xbd, 0x47, 0x24, 0x3d, + 0xd6, 0x2d, 0x9a, 0xbf, 0x28, 0xd2, 0x42, 0x3e, 0x3f, 0xf4, 0x86, 0xbf, 0x90, 0xa8, 0x1b, 0x3f, + 0x5b, 0x22, 0x1b, 0xbe, 0x46, 0x77, 0x04, 0x3f, 0x63, 0x8c, 0xba, 0xbe, 0x45, 0x27, 0xc5, 0x3f, + 0xb9, 0x8a, 0xa4, 0xbe, 0xda, 0xd1, 0x8a, 0xbd, 0x09, 0xe6, 0x53, 0xbf, 0xad, 0xad, 0x0b, 0xbf, + 0xc2, 0x14, 0x71, 0x3f, 0x15, 0x78, 0x25, 0x3f, 0x53, 0x26, 0x6a, 0xbf, 0x07, 0x3a, 0xbe, 0x3e, + 0xb9, 0x37, 0x1e, 0xbf, 0x0d, 0x07, 0x80, 0x3f, 0xd9, 0x9f, 0x01, 0x3e, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, + 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = { + -88.04056, 80.27833, 21.511183, 85.93182, 90.22253, -50.795647, 78.00544, -17.377474, + -62.31908, 14.504589, 3.2413504, 32.54737, 25.954002, 9.092799, 70.73234, -45.636135}; + +const std::vector reference_output_data = { + 26.202744, 463.3182, 84.626854, 289.90292, 0.0, 0.0, 0.0, 0.0, + 69.141045, 0.0, 31.10253, 130.52267, 5.652733, 0.0, 72.082275, 0.0, + 0.0, 128.29478, 63.66363, 136.1562, 47.363857, 197.50403, 0.0, 48.581432, + 102.55079, 0.0, 75.65965, 0.0, 0.0, 0.0, 0.0, 338.36807, + 0.0, 211.63658, 39.766064, 0.0, 215.11708, 363.6181, 0.0, 109.92663, + 0.0, 0.0, 0.0, 0.84396774, 0.0, 0.0, 161.46375, 28.506226, + 0.0, 0.0, 0.0, 92.488815, 222.40182, 48.270275, 26.44544, 0.0, + 0.0, 0.0, 51.692745, 0.0, 316.81906, 0.6861581, 0.0, 42.598343}; + +} // namespace svdf_float + +class TestDataFloatSVDF : public TestDataSVDFBase +{ +public: + TestDataFloatSVDF() + { + _input_data = svdf_float::input_data; + _reference_output_data = svdf_float::reference_output_data; + _test_kernel_model_circle = svdf_float::test_kernel_model_circle; + } + + ~TestDataFloatSVDF() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h b/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h new file mode 100644 index 00000000000..43fff152f21 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_NEG_SVDF_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_SVDF_KERNEL_H + +#include "test_models/TestDataBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_input_output_type_mismatch_svdf_kernel +{ +/* + * SVDF Kernel with input output type mismatch: + * + * Input(1, 16) - Float32 + * | + * SVDF + * | + * Output(1, 64) - Int32 + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x6c, 0x19, 0x00, 0x00, 0x60, 0x1b, 0x00, 0x00, 0x7c, 0x1b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x19, 0x00, 0x00, 0x4c, 0x19, 0x00, 0x00, 0x44, 0x19, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, + 0x1c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0xe6, 0xff, 0xff, + 0xe6, 0xf6, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc3, 0x55, 0x87, 0x3f, + 0xc4, 0xb8, 0xd9, 0xbf, 0x10, 0xa4, 0x80, 0xbe, 0x8e, 0x9f, 0x95, 0x3f, 0xc6, 0xfb, 0x45, 0xbf, + 0x52, 0x7d, 0xd3, 0x3e, 0xe0, 0xc9, 0x02, 0x3f, 0xe9, 0xd1, 0xee, 0x3d, 0xeb, 0x3a, 0xbc, 0xbf, + 0x2b, 0xc6, 0x94, 0x3f, 0x00, 0x04, 0x98, 0xbe, 0x03, 0xb9, 0x23, 0x3f, 0x52, 0x74, 0x80, 0xbf, + 0xcc, 0x61, 0x9d, 0xbf, 0x07, 0x81, 0x32, 0xbf, 0x27, 0x68, 0x0b, 0xbf, 0x0d, 0xef, 0xe7, 0xbe, + 0xbd, 0xda, 0xb1, 0xbf, 0x2e, 0xc0, 0x96, 0x3f, 0x4c, 0x5a, 0x82, 0x3e, 0xdd, 0x0d, 0x31, 0xbf, + 0x9e, 0xaa, 0x09, 0xbf, 0x04, 0xca, 0xc7, 0xbf, 0x75, 0xc6, 0x4b, 0x3e, 0x23, 0x2e, 0x94, 0x3e, + 0x54, 0x1b, 0x85, 0x3f, 0xe2, 0x42, 0xf3, 0xbf, 0x86, 0xe9, 0x10, 0xc0, 0x73, 0xb9, 0x0a, 0x3f, + 0x9a, 0xb2, 0x34, 0x3e, 0xd5, 0x03, 0x80, 0x3e, 0x51, 0x91, 0x2b, 0xbf, 0x5f, 0x5a, 0x37, 0xbf, + 0xed, 0x27, 0xec, 0x3f, 0x1e, 0x65, 0xaa, 0x3e, 0xa7, 0x3f, 0x9c, 0x3e, 0x4a, 0xf7, 0x7e, 0xbf, + 0x24, 0x57, 0xb0, 0xbf, 0xa4, 0x06, 0x61, 0x3f, 0x82, 0x86, 0xce, 0x3e, 0x99, 0x32, 0x9b, 0xbf, + 0xc9, 0xc1, 0xc3, 0x3f, 0x51, 0xed, 0x85, 0x3f, 0x8d, 0x3a, 0x30, 0x3f, 0xd4, 0xe0, 0x2a, 0xc0, + 0xf1, 0x5d, 0x92, 0xbf, 0x09, 0x85, 0x0e, 0xbf, 0x1b, 0x93, 0x0f, 0xbf, 0x80, 0xae, 0x98, 0x3e, + 0x7e, 0x7e, 0x77, 0x3f, 0xfe, 0x4b, 0x26, 0xbe, 0x77, 0x12, 0x1b, 0xbf, 0x81, 0xf5, 0xcc, 0xbe, + 0x55, 0xdd, 0x28, 0x3f, 0xad, 0x11, 0x25, 0xc0, 0xff, 0x87, 0xfd, 0x3f, 0x6f, 0x5a, 0x2e, 0x3f, + 0x59, 0x8f, 0x8e, 0x3f, 0xf0, 0x03, 0xe8, 0x3f, 0xbb, 0x41, 0x0e, 0x3f, 0x62, 0x9d, 0x0d, 0xbf, + 0xaf, 0xcc, 0xec, 0xbc, 0x71, 0x8d, 0x87, 0xbf, 0xbe, 0x72, 0x5a, 0x3f, 0xf2, 0xf7, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xd3, 0xc7, 0xee, 0x3e, 0xe8, 0x29, 0x4e, 0x40, + 0xbb, 0xc5, 0x9c, 0xbe, 0xeb, 0x24, 0x9c, 0xbf, 0xf3, 0x50, 0x92, 0xbe, 0x22, 0x9a, 0x70, 0x3f, + 0x60, 0xea, 0xcf, 0x3c, 0x25, 0x80, 0xa0, 0x3f, 0xef, 0xde, 0xb5, 0xbe, 0x04, 0x9e, 0x53, 0xbf, + 0xc4, 0xac, 0xd7, 0x3f, 0xd6, 0xef, 0xba, 0xbf, 0x19, 0x73, 0x13, 0x40, 0xec, 0x4d, 0x81, 0x3f, + 0xe1, 0xd3, 0xf3, 0x3d, 0x46, 0xb7, 0x51, 0x3f, 0x2c, 0xc7, 0x96, 0x3f, 0x6a, 0x42, 0x29, 0xbe, + 0xc7, 0x72, 0x29, 0xbd, 0x88, 0x8c, 0xa3, 0x3f, 0xf9, 0xb8, 0xf0, 0x3f, 0x39, 0xde, 0x5b, 0xbf, + 0xa5, 0x7c, 0xfc, 0x3f, 0xfe, 0xa7, 0x1d, 0xbe, 0x42, 0x6c, 0xb1, 0x3f, 0xa7, 0x06, 0x12, 0xbf, + 0x6a, 0x1d, 0x7f, 0x3f, 0x38, 0xe0, 0x4a, 0xbf, 0xdd, 0x30, 0xc4, 0xbf, 0x8a, 0x51, 0x0d, 0xbe, + 0x67, 0xef, 0x47, 0x3e, 0xad, 0x06, 0x1d, 0xbe, 0x9f, 0x53, 0xe1, 0x3f, 0x85, 0xbe, 0x38, 0xbe, + 0xe2, 0x3b, 0x82, 0xbf, 0xda, 0xce, 0x9c, 0xbf, 0x00, 0xa8, 0x20, 0xbf, 0x45, 0x30, 0x45, 0xc0, + 0x4f, 0x52, 0xe8, 0x3d, 0x08, 0x86, 0xd9, 0x3f, 0x08, 0xb4, 0x61, 0xbe, 0x92, 0x6f, 0x9e, 0x3e, + 0xba, 0xa1, 0x78, 0x3f, 0x2f, 0x86, 0xfa, 0xbe, 0x02, 0xfc, 0x98, 0x3c, 0x5c, 0x64, 0xc8, 0x3f, + 0x98, 0x48, 0x18, 0xc0, 0x53, 0xa8, 0xee, 0xbe, 0xfa, 0xe3, 0x39, 0x3f, 0x28, 0x7e, 0x23, 0xbf, + 0x26, 0xac, 0xb8, 0xbf, 0xc9, 0x35, 0x8b, 0x3f, 0xa3, 0x96, 0xb7, 0x3e, 0x3d, 0x5c, 0x9a, 0x3f, + 0xb4, 0xaa, 0xd5, 0xbf, 0x04, 0xd3, 0x93, 0xbf, 0xd6, 0xf5, 0x80, 0xbe, 0x4b, 0xf1, 0x6a, 0x3f, + 0xbd, 0xae, 0x89, 0xbb, 0x45, 0x8f, 0xaa, 0x3d, 0x52, 0xde, 0x17, 0xc0, 0xa8, 0xfe, 0x82, 0xbf, + 0x60, 0xcd, 0xf8, 0xbe, 0xfa, 0xdc, 0x25, 0x3e, 0x13, 0xd8, 0x7d, 0xbe, 0x2b, 0x7b, 0xac, 0xbf, + 0x71, 0xde, 0x8f, 0xbf, 0x48, 0xf3, 0x18, 0xbf, 0xd0, 0x50, 0x70, 0x3e, 0x12, 0x48, 0xb6, 0xbe, + 0x5e, 0xda, 0x49, 0x3f, 0x28, 0x57, 0xf8, 0x3f, 0x2e, 0x2b, 0xf4, 0x3d, 0x6f, 0xa7, 0xa3, 0x3e, + 0xd3, 0x19, 0xa9, 0xbf, 0xa1, 0x2d, 0xe4, 0xbe, 0x44, 0x66, 0x7b, 0x3e, 0x28, 0x66, 0x02, 0x3e, + 0x0b, 0xae, 0xa1, 0xbf, 0xec, 0xb1, 0x8e, 0x3e, 0x1b, 0xb5, 0x1f, 0xbf, 0xe1, 0x2c, 0xa1, 0xbe, + 0xbb, 0x0f, 0x2e, 0xbf, 0x3b, 0xb1, 0xf5, 0x3d, 0x08, 0x75, 0xeb, 0xbf, 0x3a, 0x2f, 0xa2, 0xbf, + 0x35, 0x46, 0xe6, 0xbf, 0xa6, 0xac, 0xcb, 0xbe, 0xb3, 0xb0, 0x70, 0xbf, 0x0d, 0xd4, 0x89, 0x3e, + 0x13, 0x5b, 0x3b, 0x3d, 0x89, 0x15, 0x21, 0xbf, 0x43, 0xf2, 0x93, 0xbf, 0x36, 0x8f, 0xed, 0x3f, + 0x90, 0x41, 0x17, 0xbf, 0x35, 0x6d, 0xd6, 0x3f, 0xe9, 0xa7, 0x5d, 0x3e, 0xe4, 0xcf, 0xbd, 0x3e, + 0xb7, 0xb1, 0xed, 0xbe, 0x97, 0x8a, 0xbe, 0xbf, 0xd0, 0x5e, 0xb2, 0x3e, 0x08, 0x4f, 0xb0, 0x3f, + 0x08, 0xfe, 0x2f, 0xc0, 0xc8, 0x4f, 0x97, 0x3f, 0x5e, 0x4d, 0xc3, 0x3f, 0x4f, 0x56, 0x6f, 0x3b, + 0x7a, 0xdb, 0x3f, 0x3f, 0x88, 0xb5, 0x80, 0x3e, 0xf4, 0x8b, 0x68, 0x3f, 0x32, 0xd3, 0xb8, 0x3e, + 0x37, 0x92, 0xc9, 0xbf, 0x87, 0x6d, 0x99, 0xbe, 0xd2, 0x96, 0x81, 0xbf, 0x6f, 0x47, 0xab, 0x3f, + 0x20, 0x81, 0x98, 0xbd, 0x55, 0xef, 0xe8, 0xbe, 0xb4, 0x0a, 0x93, 0xbe, 0x05, 0x3a, 0xe5, 0x3d, + 0x99, 0x94, 0x99, 0xbe, 0x1b, 0xaf, 0xe2, 0xbd, 0x9c, 0x30, 0x22, 0xbf, 0x22, 0x7f, 0xc9, 0x3f, + 0x91, 0xbc, 0x10, 0x3f, 0x29, 0xcc, 0xeb, 0x3f, 0xc0, 0x1b, 0xec, 0x3e, 0x5c, 0x5a, 0xae, 0xbf, + 0x0f, 0x5b, 0xf5, 0xbf, 0x61, 0xc9, 0x8b, 0x3f, 0x38, 0xd9, 0x1e, 0x3f, 0xf5, 0x1f, 0x82, 0x3e, + 0x99, 0x04, 0xae, 0x3f, 0x20, 0xd3, 0x00, 0x3f, 0xe7, 0x58, 0xd9, 0x3d, 0xcb, 0x1b, 0x67, 0xbf, + 0xc5, 0x95, 0x8c, 0x3f, 0x64, 0x39, 0x5b, 0x3b, 0x2a, 0x80, 0x20, 0x3f, 0x44, 0x4f, 0x1e, 0xbf, + 0x3f, 0xf4, 0xb7, 0x3e, 0x22, 0x5e, 0x45, 0xbd, 0x87, 0x00, 0x26, 0xbf, 0xa3, 0x7a, 0xc2, 0x3f, + 0xac, 0x45, 0x9b, 0xbf, 0xa4, 0x59, 0x87, 0x3e, 0x0c, 0xc1, 0x19, 0xbf, 0x78, 0x40, 0xc3, 0x3f, + 0x5a, 0x69, 0xef, 0x3f, 0x47, 0x5b, 0x8c, 0xbf, 0x10, 0x73, 0x22, 0x3f, 0xd0, 0xe0, 0x7d, 0xbf, + 0xdd, 0x87, 0xd7, 0x3d, 0x60, 0xd7, 0xd8, 0x3e, 0x2e, 0xbf, 0x47, 0x3f, 0xdb, 0x13, 0xbe, 0xbf, + 0x80, 0x90, 0xc5, 0x3e, 0xe5, 0x46, 0x62, 0x3f, 0x9d, 0x13, 0xb8, 0xbf, 0x2d, 0x31, 0x68, 0xbf, + 0xa1, 0xe4, 0x13, 0xbf, 0x91, 0xba, 0x5b, 0xbd, 0xb6, 0x07, 0xc0, 0xbf, 0x83, 0xde, 0x1f, 0xc0, + 0xb2, 0xee, 0x06, 0xbf, 0x33, 0xbf, 0x3d, 0x3f, 0x10, 0xbb, 0x64, 0x3f, 0x4d, 0x9a, 0xd2, 0xbe, + 0x85, 0xf4, 0xf8, 0xbe, 0xf9, 0x2f, 0x8a, 0xbf, 0x4f, 0xc6, 0x61, 0x3f, 0x3f, 0x19, 0xde, 0xbf, + 0x39, 0xd7, 0x83, 0xbc, 0x8a, 0xe7, 0xa9, 0xbe, 0x8f, 0x41, 0xb8, 0x3e, 0x5a, 0x75, 0xb6, 0xbe, + 0xd1, 0x33, 0x4a, 0xbe, 0xc0, 0xf4, 0x1b, 0xbf, 0xc8, 0xc4, 0xdb, 0xbe, 0xca, 0x58, 0x90, 0x3e, + 0x24, 0x3c, 0xf4, 0xbf, 0x01, 0xe5, 0x77, 0xbf, 0xc4, 0x16, 0x94, 0xbe, 0xee, 0x88, 0x65, 0x3f, + 0x34, 0xe3, 0x87, 0xbf, 0x9d, 0x7d, 0x5d, 0xbf, 0xdc, 0x18, 0x22, 0x3e, 0x39, 0x31, 0x12, 0xc0, + 0x3f, 0x6f, 0xce, 0x3f, 0x5a, 0xa4, 0x90, 0xbf, 0x9e, 0x51, 0xd0, 0xbf, 0x19, 0xb0, 0xdf, 0xbf, + 0xbf, 0x27, 0xb9, 0x3d, 0xdf, 0x28, 0x5d, 0xbf, 0x1f, 0x15, 0x07, 0xbf, 0x98, 0xfb, 0xf6, 0xbf, + 0x17, 0x2b, 0x49, 0x3e, 0x68, 0x8e, 0x0b, 0xc0, 0xbd, 0xab, 0x06, 0xbe, 0x31, 0xb5, 0x95, 0x3f, + 0x31, 0xcd, 0xb5, 0x3f, 0x1a, 0x46, 0x16, 0xbf, 0x95, 0xf0, 0xbc, 0xbe, 0xae, 0xae, 0xb3, 0xbf, + 0xb7, 0x30, 0x1b, 0x3f, 0x37, 0x42, 0xf3, 0x3f, 0x7a, 0x64, 0x01, 0xbf, 0xbc, 0x47, 0x10, 0x3f, + 0xd9, 0x9b, 0xae, 0x3f, 0x18, 0x34, 0x40, 0xbf, 0x23, 0x6f, 0x66, 0x3e, 0x4c, 0x46, 0x68, 0x3e, + 0x71, 0x4d, 0xe5, 0xbf, 0x23, 0x2b, 0xe0, 0xbc, 0x0a, 0x92, 0x27, 0xbe, 0xe6, 0x3c, 0x12, 0x3f, + 0x2b, 0x68, 0xac, 0x3f, 0x60, 0xcd, 0xb8, 0xbf, 0x37, 0x90, 0xbd, 0xbe, 0x77, 0x1a, 0xd4, 0x3f, + 0xd2, 0x67, 0x95, 0x3f, 0xf4, 0xdf, 0xd7, 0x3f, 0x3c, 0x61, 0x70, 0x3e, 0xb7, 0xfc, 0x8e, 0x3f, + 0x70, 0x89, 0x97, 0xbf, 0xc1, 0x97, 0xa3, 0xbe, 0x12, 0x8c, 0x36, 0x3e, 0x64, 0xdf, 0x83, 0xbf, + 0xd2, 0xce, 0xbc, 0x3f, 0x64, 0xbd, 0x2e, 0x3e, 0x39, 0xe6, 0x1c, 0xbf, 0x04, 0xc6, 0x43, 0xbf, + 0x5d, 0x21, 0x8a, 0x3f, 0xd8, 0x09, 0x31, 0x3f, 0x6e, 0xd6, 0xc8, 0x3d, 0x67, 0x5a, 0x22, 0xc0, + 0x72, 0xbd, 0x18, 0xbf, 0xab, 0xb6, 0x3e, 0x3e, 0x62, 0x34, 0x9f, 0xbd, 0xcc, 0x5a, 0x94, 0xbf, + 0xd5, 0x9c, 0x9b, 0xbe, 0xbc, 0x0f, 0x89, 0x3e, 0xa5, 0x30, 0x04, 0xc0, 0xa4, 0x16, 0x75, 0xbf, + 0x37, 0xea, 0x2f, 0x3e, 0xb0, 0xcd, 0xf0, 0x3e, 0x5a, 0x86, 0xe4, 0x3e, 0xe0, 0x31, 0x92, 0xbf, + 0xb5, 0x56, 0xa4, 0xbe, 0xf8, 0xf6, 0xdd, 0x3f, 0x45, 0x27, 0x25, 0xbe, 0xff, 0x8d, 0x2c, 0x3e, + 0x10, 0x84, 0x6b, 0xbf, 0x80, 0xb7, 0x95, 0x3e, 0xdf, 0xe0, 0xe0, 0x3f, 0x5e, 0xfe, 0xc7, 0xbe, + 0xd0, 0xd3, 0x8e, 0xbf, 0xcf, 0x68, 0x8d, 0x3f, 0x23, 0x49, 0x3e, 0xbf, 0x4e, 0x4c, 0x92, 0x3f, + 0x5d, 0xba, 0x8c, 0x3e, 0xf6, 0x8b, 0x4f, 0x3f, 0x0a, 0x1e, 0xf6, 0xbf, 0x28, 0xc7, 0x8d, 0x3f, + 0xcd, 0xf2, 0x12, 0xbf, 0x0b, 0x84, 0xe3, 0x3f, 0xdc, 0x9d, 0xcc, 0x3f, 0xa5, 0x46, 0x4a, 0xbf, + 0x95, 0x2d, 0x77, 0xbe, 0x64, 0x9d, 0x96, 0x3e, 0x96, 0x02, 0x7a, 0xbf, 0x4d, 0x58, 0x41, 0x3f, + 0x74, 0x5b, 0xca, 0xbf, 0x50, 0x70, 0xe1, 0x3e, 0x68, 0xa4, 0xa1, 0x3f, 0xb5, 0x10, 0x05, 0x3f, + 0x99, 0x3e, 0x37, 0x40, 0xec, 0x59, 0xc7, 0x3f, 0x56, 0x68, 0x63, 0xbf, 0x03, 0xfd, 0xd6, 0x3e, + 0x7a, 0x63, 0x84, 0x3f, 0x09, 0x18, 0x99, 0x3f, 0x3c, 0x41, 0xbb, 0x3e, 0x2c, 0x06, 0x8f, 0xbf, + 0xf1, 0x31, 0x96, 0xbe, 0x56, 0x5e, 0xdf, 0x3f, 0xa3, 0x51, 0x94, 0x3f, 0x2b, 0xc4, 0x34, 0x3e, + 0xe4, 0x0b, 0xf2, 0x3e, 0x2b, 0x4f, 0xdc, 0x3e, 0xb7, 0xbb, 0x8d, 0x3e, 0xb8, 0xfe, 0xcf, 0xbe, + 0xa1, 0xe6, 0x28, 0x3f, 0xa0, 0xa6, 0x21, 0x3f, 0xbf, 0xa8, 0xba, 0x3e, 0xe3, 0xb2, 0xb3, 0xbd, + 0x16, 0x8a, 0x09, 0x3f, 0x06, 0x3c, 0xe5, 0xbd, 0xe9, 0xcf, 0x7d, 0x3e, 0xdd, 0x8a, 0x13, 0x3f, + 0xd2, 0xd6, 0x43, 0xbf, 0xd6, 0x99, 0xad, 0xbe, 0xeb, 0xfa, 0x03, 0x40, 0xc0, 0x1e, 0xac, 0xbd, + 0x0c, 0x8a, 0x70, 0xbd, 0x8a, 0x78, 0x1a, 0xbc, 0x90, 0xc5, 0xf1, 0xbe, 0x48, 0xfc, 0xb2, 0xbe, + 0x70, 0x87, 0x50, 0xbf, 0x00, 0x5a, 0x56, 0xbf, 0xce, 0xe9, 0x28, 0x3f, 0xf6, 0x8a, 0x82, 0xbe, + 0xb1, 0x12, 0xf0, 0xbf, 0x9a, 0xbc, 0x1d, 0xbf, 0x31, 0x71, 0xec, 0x3d, 0x14, 0x67, 0x9a, 0xbc, + 0x92, 0xc1, 0x19, 0x3f, 0xcc, 0x6c, 0xe4, 0xbf, 0xde, 0x5a, 0x9f, 0x3f, 0x6d, 0xf3, 0x12, 0x3e, + 0x49, 0x3f, 0xd9, 0xbf, 0x9d, 0xc5, 0x62, 0xbe, 0x2d, 0xcd, 0xe9, 0xbe, 0xfc, 0xda, 0xc2, 0xbf, + 0x0e, 0xa1, 0x4a, 0x3d, 0xa4, 0x58, 0x04, 0x40, 0x71, 0xe1, 0x4c, 0x3f, 0x40, 0xfc, 0xd9, 0x3d, + 0xa3, 0x49, 0x03, 0x3f, 0xbe, 0xaa, 0x5e, 0x3e, 0xde, 0x4e, 0x07, 0x40, 0xe2, 0x20, 0x17, 0x3f, + 0xe0, 0x35, 0xe2, 0x3f, 0xad, 0x18, 0x1d, 0xbd, 0x67, 0xbb, 0x13, 0xbf, 0x9d, 0x36, 0xb6, 0x3e, + 0x09, 0x38, 0x38, 0xbf, 0x6d, 0x88, 0x01, 0x3e, 0x3c, 0x4e, 0x84, 0x3f, 0x71, 0xc2, 0x0a, 0xbf, + 0x2b, 0x80, 0x91, 0xbe, 0x99, 0x77, 0x7f, 0xbf, 0x07, 0xa4, 0x0a, 0x3c, 0xaf, 0xd3, 0x8a, 0xbe, + 0x4b, 0xfb, 0x83, 0x3f, 0x48, 0x45, 0xcb, 0x3e, 0x67, 0x7e, 0xf2, 0x3e, 0x53, 0xde, 0x2b, 0x3f, + 0xc7, 0xec, 0x1a, 0x3d, 0x15, 0x3a, 0xad, 0x3e, 0x09, 0x7e, 0xaa, 0x3e, 0xf2, 0xa6, 0x89, 0xbd, + 0xa4, 0x0c, 0xb9, 0xbe, 0xb1, 0x65, 0x31, 0x3e, 0x51, 0x9e, 0x29, 0xbf, 0xd5, 0x74, 0x6b, 0x3f, + 0x69, 0x68, 0x52, 0x3e, 0xeb, 0xc3, 0x21, 0xbf, 0x72, 0xa0, 0xf3, 0x3d, 0x74, 0x2f, 0x31, 0xbe, + 0x1c, 0xf3, 0x21, 0x3e, 0x70, 0xce, 0xe7, 0x3e, 0xb3, 0x88, 0x7a, 0x3e, 0x94, 0x86, 0x8d, 0xbf, + 0x0a, 0x11, 0x15, 0x3f, 0x57, 0xfc, 0x24, 0x3f, 0x5f, 0x2c, 0x3c, 0x3f, 0xbc, 0xb4, 0xcb, 0xbf, + 0x71, 0x91, 0xd6, 0xbf, 0x46, 0x77, 0xa2, 0xbd, 0xa7, 0x30, 0x8b, 0xbf, 0x5b, 0xfb, 0x51, 0xbf, + 0xc6, 0x06, 0xaf, 0xbd, 0x65, 0xb8, 0x5a, 0x3e, 0xb5, 0x0d, 0xb4, 0xbf, 0xe6, 0xa1, 0xa5, 0xbe, + 0x15, 0xaa, 0xb5, 0xbe, 0x0a, 0x1d, 0xd2, 0xbf, 0x4e, 0x6e, 0x1c, 0xbf, 0x35, 0xec, 0x50, 0x3d, + 0xe1, 0x1b, 0x32, 0x3f, 0xee, 0xe0, 0x0c, 0xbd, 0x78, 0x81, 0xdc, 0x3e, 0x32, 0xa0, 0x4d, 0x3e, + 0x49, 0xa3, 0x0c, 0xc0, 0x0b, 0xa0, 0x38, 0xbf, 0x1f, 0x78, 0x4a, 0xbf, 0xa2, 0xef, 0x18, 0xbf, + 0x1b, 0x81, 0xb2, 0x3f, 0x4d, 0x72, 0x98, 0x3f, 0x61, 0xbe, 0x12, 0xbf, 0xc7, 0x6f, 0xdf, 0xbd, + 0x4e, 0x87, 0x98, 0x3f, 0x3d, 0x23, 0x1d, 0x3d, 0x8f, 0x10, 0x41, 0xbf, 0x6b, 0x4c, 0x63, 0x3f, + 0x0d, 0x64, 0xf9, 0xbe, 0xc7, 0xdd, 0x20, 0xbf, 0xe8, 0x2b, 0xa7, 0xbf, 0x2d, 0xb4, 0x7c, 0xbe, + 0xa0, 0x5a, 0xe8, 0x3e, 0xd2, 0xd3, 0x55, 0x3f, 0x2d, 0x60, 0x91, 0xbe, 0xc2, 0x9f, 0xb5, 0x3f, + 0xf5, 0x63, 0x3c, 0x3f, 0xca, 0x48, 0x92, 0xbf, 0xc5, 0xf8, 0x0a, 0x3f, 0x0a, 0x6a, 0x31, 0x3d, + 0xea, 0x1a, 0x43, 0x3f, 0x2a, 0x48, 0xa6, 0xbf, 0x62, 0x30, 0x31, 0x3f, 0xcc, 0x53, 0x93, 0xbf, + 0x12, 0x96, 0x3b, 0x3f, 0x6e, 0xa1, 0xc4, 0x3f, 0xd2, 0xae, 0x06, 0xbc, 0xd1, 0xdd, 0xbb, 0xbf, + 0xea, 0x3a, 0x7e, 0xbf, 0xcb, 0x67, 0x9c, 0x3e, 0x1a, 0x9f, 0x44, 0xbf, 0x6c, 0xd5, 0x2f, 0xbf, + 0xc9, 0xe9, 0x8f, 0xbe, 0xe6, 0xf1, 0x90, 0x3c, 0x35, 0x83, 0xac, 0xbf, 0x6c, 0xc0, 0xca, 0x3f, + 0x81, 0x21, 0x90, 0x3f, 0x51, 0x96, 0xdc, 0xbf, 0xd6, 0x4a, 0xa4, 0xbf, 0x5d, 0x9e, 0x77, 0xbf, + 0x49, 0x63, 0x2d, 0x3f, 0xf0, 0x1e, 0xc8, 0xbf, 0x17, 0xf7, 0xd9, 0x3f, 0xdc, 0xbb, 0xe4, 0x3f, + 0x31, 0x5e, 0x38, 0x3f, 0xf8, 0xc1, 0xa5, 0xbf, 0x33, 0x50, 0xe2, 0xbe, 0xb0, 0x33, 0x80, 0x3f, + 0x1b, 0xd2, 0x45, 0x3e, 0x31, 0x16, 0xc4, 0x3f, 0x2e, 0x45, 0x2d, 0xbf, 0xc9, 0x3f, 0x8a, 0xbe, + 0x4b, 0x6e, 0x7c, 0xbe, 0x78, 0xbf, 0x39, 0xbe, 0x72, 0x8d, 0x3f, 0xbf, 0x66, 0x0a, 0xd9, 0x3e, + 0x17, 0xe3, 0x47, 0x3f, 0x50, 0x01, 0x58, 0x3f, 0x00, 0x56, 0x1c, 0xbf, 0xd9, 0xcd, 0x5f, 0x3f, + 0x7e, 0x31, 0xd3, 0xbf, 0xf3, 0x4e, 0x5f, 0xbf, 0x49, 0xdd, 0x9c, 0xbf, 0x17, 0xb7, 0x32, 0x3d, + 0x28, 0xfe, 0xa9, 0x3e, 0x0a, 0xc5, 0x33, 0x3c, 0x46, 0x83, 0xec, 0x3f, 0xcf, 0x56, 0x9b, 0xbf, + 0xe1, 0xf2, 0x0e, 0x3d, 0x52, 0xfe, 0x6c, 0x3f, 0xe0, 0x3c, 0x92, 0xbe, 0x88, 0xed, 0x8c, 0xbf, + 0x53, 0x61, 0xf6, 0x3e, 0xe9, 0xe7, 0x02, 0x3e, 0xf1, 0x9d, 0x93, 0xbd, 0xa5, 0x17, 0x74, 0xbf, + 0x78, 0x1e, 0xda, 0x3f, 0xc7, 0x7d, 0x00, 0x3f, 0x8a, 0xbd, 0x47, 0x3e, 0x3d, 0xcb, 0xac, 0xbf, + 0x30, 0xcc, 0x96, 0x3f, 0x22, 0x5c, 0x9c, 0xbf, 0xf3, 0xec, 0x26, 0x40, 0xe3, 0x7d, 0xaa, 0x3f, + 0x22, 0xdb, 0x04, 0x3f, 0x33, 0x03, 0x97, 0x3f, 0xce, 0x27, 0xdf, 0xbe, 0x03, 0x0d, 0xec, 0x3e, + 0xad, 0xb0, 0x33, 0x3f, 0x65, 0x39, 0x4e, 0xbf, 0xc2, 0xac, 0x8f, 0xbe, 0x6a, 0xe8, 0xd7, 0xbf, + 0xd1, 0xae, 0x99, 0x3f, 0x6d, 0x13, 0x3e, 0x3f, 0x15, 0x4f, 0xb6, 0xbf, 0xd0, 0x38, 0x5c, 0xbf, + 0xc3, 0xb8, 0xae, 0x3f, 0x30, 0xd3, 0xf2, 0xbe, 0xce, 0x78, 0x7d, 0x3d, 0x40, 0x01, 0xce, 0x3d, + 0x61, 0x55, 0xc5, 0xbe, 0x8a, 0xb0, 0x9d, 0x3f, 0x5d, 0x8e, 0x59, 0x3f, 0xca, 0xf9, 0x95, 0xbf, + 0x68, 0xd8, 0xd9, 0xbf, 0x8a, 0x9e, 0xa2, 0x3f, 0x42, 0x18, 0xe6, 0xbf, 0xda, 0xf7, 0xed, 0x3f, + 0x5b, 0x02, 0xf2, 0x3f, 0x1d, 0x80, 0x99, 0xbf, 0x05, 0x6f, 0x0e, 0x40, 0x86, 0xa9, 0xa2, 0x3e, + 0x7e, 0x3d, 0xe7, 0x3f, 0x24, 0x13, 0x9b, 0xbf, 0x79, 0x66, 0xaa, 0x3f, 0xed, 0x09, 0x31, 0xbf, + 0x90, 0x3f, 0xc0, 0x3f, 0x05, 0xfc, 0x9d, 0x3f, 0xd4, 0x9f, 0x9c, 0xbf, 0x45, 0x84, 0x22, 0x3f, + 0xbc, 0x6b, 0x4d, 0xbf, 0xdb, 0x8c, 0x8c, 0xbf, 0xcb, 0xdf, 0x7d, 0xbf, 0xd5, 0xb7, 0xb7, 0xbf, + 0x1e, 0xf5, 0xb8, 0xbf, 0xe9, 0x64, 0x94, 0xbf, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xc4, 0x03, 0x56, 0xbe, + 0x11, 0x52, 0x42, 0xbf, 0xe6, 0xd6, 0x1a, 0xbe, 0xf6, 0xe7, 0x9e, 0xbd, 0x64, 0x6a, 0xc9, 0x3e, + 0xc3, 0x73, 0xd6, 0x3c, 0x31, 0x19, 0x1b, 0x3e, 0x9c, 0x6f, 0x97, 0x3f, 0x9c, 0x48, 0x73, 0xbe, + 0x6c, 0x01, 0xcc, 0xbe, 0x94, 0x04, 0x79, 0xbf, 0xd2, 0x1b, 0x92, 0xbf, 0x8b, 0xee, 0xdb, 0xbf, + 0x87, 0x3a, 0x36, 0xbe, 0xec, 0x19, 0x39, 0x3f, 0x73, 0xe8, 0xb8, 0x3f, 0xda, 0x91, 0xed, 0x3f, + 0xa9, 0xf3, 0x3a, 0xbf, 0xad, 0x10, 0x39, 0x3f, 0x62, 0x46, 0xab, 0xbf, 0xe5, 0xd6, 0xa7, 0x3f, + 0x97, 0xb8, 0x99, 0xbe, 0x22, 0x1c, 0xd7, 0xbe, 0x30, 0xfb, 0x14, 0x40, 0xce, 0x87, 0x8a, 0xbe, + 0xfa, 0xc6, 0x8a, 0xbf, 0xbf, 0x9d, 0xab, 0xbf, 0x25, 0xb7, 0x00, 0x40, 0xca, 0xdf, 0x5d, 0xbf, + 0xd0, 0xd5, 0xb7, 0xbf, 0x64, 0xb4, 0x5b, 0xbe, 0x8e, 0xd3, 0x3e, 0xc0, 0xa2, 0x75, 0xb9, 0x3e, + 0x8b, 0x23, 0x84, 0x3e, 0xb5, 0xb7, 0xcf, 0x3f, 0xbc, 0xcb, 0xdc, 0x3e, 0xbe, 0x8d, 0x35, 0x3f, + 0x93, 0x12, 0xb2, 0x3e, 0xd4, 0x32, 0x5c, 0xbb, 0x81, 0x4d, 0xce, 0x3f, 0x77, 0x79, 0x0e, 0xbf, + 0xed, 0x9e, 0xa4, 0xbf, 0x25, 0x26, 0x86, 0xbe, 0x76, 0xb3, 0x8b, 0x3f, 0x6f, 0xf4, 0x58, 0xbf, + 0xb8, 0x1b, 0xfa, 0x3e, 0xbe, 0x72, 0x58, 0xbf, 0x4f, 0xaf, 0x61, 0x3f, 0x01, 0x84, 0x8f, 0xbf, + 0xe7, 0xc1, 0x64, 0x3f, 0xe2, 0x63, 0xb1, 0xbf, 0xc9, 0xad, 0x5c, 0x3f, 0xca, 0x88, 0xd9, 0x3f, + 0xd8, 0x70, 0x04, 0x3f, 0xdd, 0x06, 0xd0, 0xbe, 0x4a, 0xac, 0x91, 0xbe, 0x6a, 0x8e, 0x00, 0x3f, + 0x5b, 0x9a, 0xd1, 0x3f, 0xba, 0x37, 0xda, 0xbb, 0x58, 0x93, 0x12, 0x3e, 0xee, 0xbe, 0x57, 0xbf, + 0x0c, 0x6b, 0x26, 0x40, 0x64, 0x64, 0x85, 0x3d, 0x0a, 0x86, 0xd0, 0xbf, 0xa0, 0xa5, 0xe2, 0xbf, + 0x6f, 0xe5, 0xb5, 0x3f, 0x58, 0xa1, 0x10, 0x3c, 0x87, 0x14, 0xb2, 0xbf, 0x81, 0x11, 0xa8, 0x3e, + 0x28, 0x3d, 0x32, 0x3f, 0x57, 0x26, 0x86, 0xbf, 0xd6, 0x6f, 0x16, 0x3f, 0x16, 0x2f, 0xa4, 0x3f, + 0xc9, 0x13, 0x9b, 0x3f, 0xb1, 0x4e, 0xa2, 0xbf, 0x47, 0x0e, 0x7c, 0x3e, 0x98, 0xdd, 0xe5, 0xbe, + 0xab, 0x11, 0xd1, 0x3f, 0xd9, 0x67, 0x00, 0xc0, 0xae, 0xbc, 0x9d, 0x3f, 0x93, 0x4e, 0x42, 0xc0, + 0xb7, 0x1b, 0xfa, 0x3f, 0xef, 0xd6, 0xe3, 0xbf, 0x3a, 0x3c, 0x57, 0x3e, 0x57, 0x1b, 0x97, 0xbf, + 0x88, 0x83, 0xb5, 0xbf, 0x03, 0x60, 0xe6, 0x3e, 0x4a, 0x5d, 0x99, 0xbe, 0xb9, 0x4d, 0xa4, 0xbc, + 0x82, 0x99, 0x1c, 0xbf, 0xb7, 0x08, 0x80, 0xbf, 0x88, 0xb5, 0x9d, 0xbf, 0x22, 0x75, 0xff, 0xbd, + 0xaa, 0x4d, 0x35, 0x3e, 0x3a, 0xba, 0xfe, 0xbe, 0xe7, 0x38, 0x8f, 0xbf, 0x3e, 0xc3, 0xb3, 0x3d, + 0x35, 0xff, 0xb6, 0xbf, 0xdd, 0xdd, 0x98, 0xbf, 0x4f, 0xb9, 0xd4, 0x3f, 0xd2, 0xeb, 0xe2, 0x3e, + 0xa0, 0xfc, 0xaf, 0xbf, 0x60, 0x49, 0x06, 0xc0, 0x2b, 0x97, 0xf9, 0xbe, 0x23, 0x94, 0xef, 0xbc, + 0xe8, 0xf9, 0x9f, 0xbe, 0x66, 0x00, 0x85, 0xbf, 0x7b, 0x74, 0x21, 0x3f, 0xba, 0xe4, 0x1c, 0xbe, + 0x9a, 0x89, 0x17, 0xbe, 0xaa, 0xeb, 0x42, 0xbe, 0x17, 0xd7, 0xb1, 0xbf, 0x24, 0x9a, 0xe4, 0xbe, + 0x44, 0x5f, 0xba, 0x3e, 0xeb, 0x0c, 0x27, 0xbf, 0x86, 0xa9, 0xae, 0xbe, 0x9d, 0x0f, 0xe2, 0x3e, + 0xe3, 0xce, 0xb1, 0x3e, 0xc2, 0x09, 0xbc, 0xbc, 0xe0, 0xa4, 0x0a, 0x3f, 0xac, 0x7c, 0xd9, 0x3e, + 0x57, 0x9d, 0x45, 0x3f, 0xb1, 0xc0, 0x43, 0xbf, 0x7a, 0x23, 0x22, 0x3f, 0xd1, 0x82, 0x2d, 0x3f, + 0x70, 0x7c, 0x3a, 0xbf, 0xc5, 0x47, 0xad, 0x3f, 0x13, 0x7c, 0x2d, 0xbf, 0x7a, 0x6a, 0x85, 0x3f, + 0xf0, 0x8d, 0xe6, 0x3f, 0xd4, 0x6b, 0x9c, 0x3f, 0x25, 0x8d, 0x71, 0x3f, 0x77, 0x3b, 0x91, 0x3f, + 0x31, 0x8e, 0xfb, 0x3e, 0xd8, 0xcd, 0xda, 0x3f, 0xdc, 0x12, 0x9c, 0x3f, 0x58, 0xb6, 0x9e, 0xbf, + 0xc8, 0xe0, 0x9b, 0x3f, 0xf0, 0xcb, 0xc5, 0x3d, 0x15, 0xbc, 0x9b, 0xbf, 0xd5, 0x43, 0xdf, 0x3f, + 0x61, 0xfb, 0xb9, 0x3e, 0xbf, 0x41, 0xbf, 0x3d, 0x3d, 0x36, 0x33, 0x3d, 0xbc, 0x8a, 0xa5, 0x3c, + 0xa6, 0x74, 0x42, 0xbf, 0x8b, 0xf6, 0x4b, 0xbe, 0xb7, 0x70, 0xea, 0xbf, 0x99, 0xd3, 0x40, 0x3f, + 0xa2, 0x8e, 0x7f, 0x3e, 0x69, 0xc6, 0x46, 0x3f, 0x68, 0x08, 0xae, 0xbe, 0x30, 0x2e, 0xb6, 0xbf, + 0xd5, 0x34, 0x9d, 0xbf, 0x4a, 0x66, 0x22, 0xbd, 0x70, 0x85, 0x40, 0x3f, 0x93, 0xb6, 0x71, 0xbe, + 0x96, 0xdc, 0xbc, 0x3f, 0x7b, 0x83, 0x8a, 0xbf, 0x6a, 0x89, 0x8f, 0x3f, 0x57, 0xe0, 0xe2, 0x3e, + 0x12, 0xf1, 0xfc, 0x3f, 0x20, 0x6c, 0x91, 0x3f, 0x7a, 0x19, 0x0d, 0x3f, 0xcc, 0x2c, 0x66, 0x3f, + 0x91, 0x6b, 0x86, 0xbe, 0x9b, 0xe0, 0x9b, 0x3f, 0x29, 0xd5, 0xfa, 0x3e, 0xe2, 0x25, 0xe9, 0x3c, + 0x8d, 0x3d, 0x12, 0xc0, 0x55, 0xe5, 0xb4, 0x3d, 0x17, 0x13, 0xa2, 0x3e, 0x75, 0xc0, 0x9c, 0xbf, + 0x5f, 0xa0, 0xf1, 0xbd, 0x4a, 0x61, 0x09, 0x3d, 0x28, 0xef, 0x1b, 0x3f, 0xd4, 0x3b, 0x28, 0xbf, + 0x61, 0xf3, 0x24, 0x40, 0x44, 0x7f, 0xd5, 0xbf, 0x36, 0xc8, 0x53, 0xbf, 0x9c, 0x28, 0x27, 0x3e, + 0x85, 0xf9, 0x70, 0xbf, 0xcc, 0xed, 0x89, 0x3e, 0x63, 0x81, 0x87, 0xbf, 0x1f, 0xe6, 0xea, 0x3d, + 0x97, 0xbd, 0xf8, 0x3e, 0x14, 0xbc, 0x37, 0xbf, 0xba, 0xaf, 0x31, 0xbf, 0x6d, 0x46, 0x15, 0x3e, + 0xd8, 0x04, 0x4e, 0xbf, 0x45, 0x76, 0x2d, 0xbf, 0x28, 0xe9, 0xfb, 0x3f, 0x9e, 0x67, 0xbd, 0xbf, + 0xb8, 0x4c, 0x59, 0x40, 0x91, 0xda, 0x4c, 0x3f, 0x58, 0x88, 0x6e, 0x3d, 0xfd, 0xaf, 0x29, 0xbd, + 0xff, 0xe6, 0x39, 0xbf, 0x71, 0x82, 0x84, 0x3e, 0x5c, 0xf3, 0x8c, 0xbf, 0x16, 0x1b, 0x3a, 0x3f, + 0x31, 0x06, 0x8e, 0x3f, 0x2a, 0x22, 0x99, 0xbd, 0xf9, 0x44, 0x32, 0xbf, 0xa4, 0x47, 0xae, 0x3e, + 0x9c, 0x76, 0xd8, 0xbe, 0xf9, 0xae, 0x40, 0xbf, 0xd6, 0xb4, 0x97, 0x3f, 0xb4, 0xa9, 0x52, 0xbe, + 0x25, 0x7f, 0x44, 0xbf, 0xff, 0xc4, 0xa4, 0xbf, 0x59, 0x65, 0x8f, 0x3f, 0x2a, 0xaa, 0x46, 0xbf, + 0xc0, 0x3f, 0xdb, 0xbe, 0x7e, 0xbc, 0xb3, 0xbe, 0x1b, 0x1a, 0x24, 0x3f, 0xf5, 0xa7, 0xf1, 0x3e, + 0x72, 0x28, 0x9e, 0x3e, 0x85, 0xb8, 0xc8, 0x3e, 0xf0, 0x0f, 0x08, 0xbf, 0xbd, 0xcf, 0x26, 0xbe, + 0x78, 0x4b, 0xe6, 0xbe, 0x29, 0x7d, 0xc5, 0x3e, 0x68, 0xf6, 0x98, 0x3e, 0xbd, 0xf9, 0xac, 0x3f, + 0x00, 0xbf, 0x3e, 0xbe, 0xf6, 0x7a, 0x0e, 0xc0, 0x9d, 0xb7, 0x3e, 0xbf, 0x05, 0x35, 0x6c, 0x3f, + 0xcd, 0x8f, 0x46, 0x3f, 0x23, 0xd6, 0xb0, 0x3f, 0x3c, 0xec, 0x14, 0xbf, 0x18, 0x98, 0x32, 0x3b, + 0x6c, 0x5a, 0x56, 0xbf, 0xae, 0xe0, 0xa8, 0xbf, 0xfe, 0xad, 0xaf, 0xbe, 0x7d, 0x3f, 0x99, 0x3e, + 0xf5, 0x21, 0x5b, 0xbc, 0xec, 0xf1, 0xbf, 0x3e, 0x0d, 0xae, 0x67, 0x3f, 0xb7, 0xb3, 0xa8, 0x3d, + 0xc9, 0x64, 0xdf, 0xbf, 0xeb, 0xaa, 0xcb, 0xbd, 0x8c, 0x1c, 0xc1, 0x3e, 0xbd, 0xb0, 0x72, 0xbf, + 0x88, 0x99, 0x03, 0xbf, 0x64, 0x43, 0x60, 0xbf, 0xef, 0xc2, 0x8c, 0xbd, 0xff, 0x6a, 0xa4, 0xbf, + 0x39, 0xff, 0x96, 0x3f, 0xb6, 0x67, 0x66, 0xbf, 0xba, 0x5f, 0xe6, 0xbf, 0x29, 0x19, 0x2a, 0xbe, + 0x5e, 0x60, 0xa1, 0x3e, 0xb8, 0xfd, 0x7c, 0x3f, 0x68, 0xd0, 0x56, 0x3f, 0xe6, 0x1e, 0xf9, 0xbf, + 0xe0, 0x4b, 0x86, 0x3f, 0xd9, 0xf7, 0x88, 0x3e, 0x88, 0x17, 0x87, 0x3f, 0x2a, 0x5d, 0x95, 0xbf, + 0xd0, 0xaf, 0x50, 0x3f, 0x78, 0xe4, 0xfb, 0xbe, 0x75, 0xa1, 0x88, 0xbf, 0x86, 0xdc, 0x93, 0xbe, + 0xbf, 0x66, 0xa3, 0xbf, 0x83, 0xf3, 0xbd, 0xbe, 0x39, 0x86, 0x99, 0xbe, 0xd9, 0xb5, 0x29, 0x40, + 0xf8, 0x67, 0xa3, 0xbf, 0xd6, 0x9d, 0xb7, 0xbf, 0x71, 0x74, 0x81, 0xbf, 0x12, 0x7a, 0x5b, 0xbf, + 0xa2, 0xc0, 0xe6, 0x3e, 0x37, 0xc6, 0x36, 0x3f, 0x24, 0xf5, 0xd1, 0xbf, 0xdf, 0xa6, 0x82, 0xbe, + 0x5c, 0x71, 0xea, 0xbd, 0x09, 0x5b, 0xab, 0xbd, 0xf5, 0x26, 0xce, 0x3f, 0xe7, 0xe2, 0x7a, 0x3f, + 0x3a, 0x39, 0xe0, 0x3e, 0x34, 0x5c, 0x26, 0xbf, 0xb1, 0x30, 0x1b, 0x3f, 0x31, 0xf9, 0xd4, 0x3e, + 0x48, 0xc1, 0x44, 0xbf, 0x1c, 0xf3, 0x92, 0xbf, 0x7e, 0x0d, 0x53, 0x3f, 0xc2, 0x80, 0x25, 0xbf, + 0x02, 0x3c, 0x17, 0x3e, 0x95, 0x61, 0x84, 0xbe, 0x89, 0x55, 0xe0, 0x3e, 0x8e, 0xa1, 0xd3, 0x3f, + 0x90, 0xa7, 0xee, 0xbe, 0x8f, 0xd2, 0x9b, 0xbe, 0x56, 0x39, 0x07, 0xbf, 0x19, 0x67, 0xda, 0x3f, + 0x16, 0x68, 0x9a, 0xbf, 0x71, 0xb6, 0x11, 0x3f, 0x64, 0x3f, 0xb5, 0x3f, 0x6c, 0x01, 0x1d, 0xbf, + 0x23, 0x94, 0x85, 0xbf, 0x31, 0x56, 0xb8, 0xbf, 0xd7, 0x92, 0x29, 0xbf, 0xb0, 0x14, 0x70, 0x3f, + 0x4f, 0x6b, 0xbd, 0xbe, 0x4e, 0xe9, 0x88, 0xbf, 0xd5, 0xa3, 0xf8, 0xbd, 0xa3, 0xa2, 0x84, 0x3f, + 0x48, 0x39, 0x04, 0x3e, 0xe2, 0x65, 0x8f, 0xbe, 0xa9, 0x43, 0x64, 0xbf, 0xdc, 0x72, 0x8d, 0xbf, + 0xb1, 0x21, 0x68, 0x3f, 0x25, 0x73, 0xd8, 0xbe, 0xdb, 0x94, 0x24, 0x3f, 0xe9, 0x18, 0x33, 0xbe, + 0x03, 0xb1, 0x31, 0xbf, 0x93, 0xf8, 0xa2, 0xbd, 0x31, 0x65, 0xd3, 0xbf, 0x8e, 0xcc, 0x44, 0xbd, + 0xc6, 0x5e, 0x38, 0xbf, 0x03, 0x74, 0x33, 0xc0, 0x08, 0x37, 0x57, 0x3e, 0x40, 0xc3, 0x19, 0xbe, + 0xe1, 0x18, 0x7a, 0xbe, 0x23, 0xe2, 0x18, 0xbf, 0xef, 0x0e, 0x2c, 0x3f, 0x1b, 0x2d, 0x77, 0xbf, + 0x3d, 0xa2, 0xe3, 0x3d, 0xb9, 0x23, 0x26, 0x3f, 0x66, 0x32, 0xee, 0x3f, 0xfb, 0xe5, 0xed, 0xbe, + 0x97, 0x06, 0xec, 0xbe, 0x79, 0x50, 0xf2, 0x3e, 0x1d, 0xbd, 0x93, 0xbf, 0xf3, 0x29, 0xdd, 0xbd, + 0xa0, 0x78, 0x90, 0x3f, 0x01, 0x2b, 0xa4, 0xbf, 0x01, 0x44, 0xd5, 0x3e, 0xbc, 0x26, 0x5e, 0x3f, + 0x37, 0xf2, 0x6b, 0x3e, 0x14, 0x5a, 0x98, 0x3e, 0x94, 0xe3, 0x0f, 0x40, 0x6c, 0x3a, 0xec, 0x3f, + 0x28, 0x0e, 0xcb, 0x3f, 0x1f, 0xf0, 0x85, 0x3f, 0xc8, 0x86, 0x87, 0xbf, 0xed, 0x86, 0xa0, 0xbe, + 0xb4, 0x41, 0xf3, 0x3d, 0x73, 0xb1, 0x9a, 0xbe, 0x30, 0xce, 0xb1, 0x3f, 0x44, 0x3e, 0xcd, 0xbf, + 0x81, 0x19, 0xc9, 0xbe, 0x4e, 0x14, 0x7e, 0xbf, 0x8e, 0x00, 0x7c, 0x3f, 0x54, 0xaf, 0x2b, 0x3f, + 0xc4, 0xa4, 0x11, 0x3f, 0xa8, 0x1b, 0xe4, 0x3e, 0xc8, 0x01, 0xf3, 0x3f, 0xfd, 0xdb, 0x48, 0x3f, + 0xb2, 0x38, 0x07, 0x3e, 0xbe, 0xfa, 0xf3, 0xbf, 0x5d, 0xdb, 0x19, 0xc0, 0xf2, 0xd9, 0x98, 0xbe, + 0x35, 0x97, 0xd9, 0x3e, 0x59, 0x28, 0x41, 0xbf, 0xc5, 0x56, 0x90, 0x3e, 0xdb, 0xc6, 0x54, 0xbf, + 0x6c, 0xa9, 0xbc, 0x3e, 0xd7, 0x20, 0x14, 0xbf, 0xea, 0xe3, 0x7f, 0xbd, 0xb6, 0xdf, 0x04, 0x3f, + 0x50, 0x66, 0x5c, 0x3e, 0x87, 0xa7, 0x83, 0xbe, 0x44, 0x0a, 0x28, 0x3e, 0x3c, 0x05, 0x30, 0x3e, + 0x44, 0x3d, 0x09, 0x3f, 0x4d, 0x64, 0x9a, 0xbf, 0x4f, 0xd4, 0x82, 0xbd, 0x68, 0x62, 0x69, 0x3e, + 0x54, 0x0f, 0x9a, 0x3f, 0x3b, 0x24, 0x3c, 0xbf, 0x80, 0x89, 0x8a, 0xbe, 0xab, 0x1a, 0x82, 0x3f, + 0x9a, 0x80, 0xe3, 0x3e, 0x93, 0xe0, 0x3b, 0x3f, 0xe4, 0x87, 0xc0, 0x3e, 0x1f, 0xa9, 0x3e, 0x3f, + 0x18, 0x8b, 0x56, 0xbe, 0xc5, 0xff, 0xcb, 0xbe, 0xb5, 0xc7, 0x7e, 0x3d, 0x67, 0xfe, 0x51, 0x3e, + 0x74, 0x59, 0x80, 0x3f, 0xbb, 0x71, 0x75, 0x3f, 0x4e, 0x8b, 0x8a, 0x3f, 0xb9, 0x19, 0x82, 0x3f, + 0x51, 0x16, 0xdd, 0xbf, 0x8d, 0x7b, 0x90, 0x3d, 0xc4, 0xcd, 0x56, 0xbf, 0x4d, 0xd9, 0xff, 0xbe, + 0xa9, 0x8f, 0x1b, 0xbf, 0x76, 0x50, 0xbe, 0x3e, 0x7a, 0x25, 0xf1, 0xbf, 0x6a, 0x42, 0x9f, 0xbe, + 0xe4, 0x58, 0x66, 0x3f, 0xd5, 0xad, 0x49, 0x3f, 0x29, 0xeb, 0x2f, 0x3f, 0x1b, 0x8e, 0xeb, 0xbf, + 0x4f, 0x75, 0x6e, 0x3f, 0x03, 0x16, 0x11, 0xbe, 0xa2, 0x35, 0xa2, 0xbc, 0xba, 0x67, 0x64, 0xbf, + 0x66, 0x3a, 0x1c, 0xbf, 0xfc, 0xb5, 0xc1, 0x3e, 0xca, 0x46, 0xf9, 0x3f, 0xd0, 0xa7, 0x03, 0x3f, + 0x45, 0xde, 0x87, 0xbf, 0xde, 0x93, 0x04, 0x3f, 0x98, 0x2d, 0x19, 0x40, 0x70, 0x8e, 0x99, 0x3f, + 0x98, 0xb8, 0xf9, 0xbf, 0xf1, 0x7e, 0xb1, 0x3d, 0x7d, 0x7e, 0x3b, 0xbf, 0x50, 0xc2, 0xc6, 0xbe, + 0xe8, 0xb4, 0x8d, 0xbf, 0xdb, 0x6a, 0x1c, 0xc0, 0x85, 0x23, 0xd4, 0xbe, 0xea, 0x03, 0xf2, 0xbe, + 0xc4, 0x51, 0xf9, 0x3e, 0x5d, 0xd5, 0x9c, 0xbc, 0x30, 0x93, 0x9f, 0x3e, 0x0b, 0x8c, 0x24, 0xbf, + 0xf9, 0x6f, 0x0c, 0xc0, 0x19, 0x92, 0x27, 0x40, 0x7e, 0xe5, 0x8d, 0xbf, 0x1b, 0xed, 0x60, 0xbd, + 0x36, 0x80, 0xba, 0xbf, 0xda, 0xb1, 0x60, 0xbf, 0x0b, 0xe7, 0x47, 0xbf, 0xd7, 0x50, 0x14, 0x3f, + 0xab, 0x11, 0x85, 0xbf, 0xd8, 0x58, 0x15, 0x3e, 0x46, 0x8e, 0x01, 0xbf, 0x25, 0x96, 0x5c, 0xbf, + 0x23, 0xe2, 0xcc, 0xbe, 0xa5, 0x97, 0x3f, 0xbf, 0xa0, 0xec, 0x9a, 0xbf, 0x60, 0x54, 0x9b, 0x3f, + 0x6d, 0x92, 0x41, 0x3f, 0x74, 0xeb, 0x03, 0xbd, 0x49, 0xe2, 0x9b, 0x3f, 0x22, 0x80, 0x1b, 0x3f, + 0x9d, 0xa2, 0xfe, 0xbe, 0xb6, 0x93, 0xec, 0x3f, 0x6a, 0x38, 0x09, 0xc0, 0x27, 0x72, 0x89, 0xbe, + 0xe6, 0x0e, 0x33, 0xbe, 0xbd, 0x5c, 0x92, 0x3f, 0x13, 0x3b, 0xa1, 0xbf, 0xab, 0x05, 0x13, 0x3f, + 0x30, 0x84, 0x8c, 0x3c, 0xd7, 0xca, 0x02, 0x3f, 0xb0, 0x17, 0x6b, 0xbf, 0x5d, 0x34, 0x9a, 0xbf, + 0xa3, 0x50, 0x1b, 0x40, 0x9f, 0x12, 0xbd, 0x3e, 0xfa, 0x5d, 0x82, 0x3f, 0x86, 0xf6, 0x7e, 0x3f, + 0x1e, 0x8e, 0xf2, 0xbf, 0xfc, 0xbc, 0x15, 0xbf, 0xe4, 0xf7, 0xe8, 0xbe, 0xde, 0x5b, 0xb6, 0xbe, + 0x1f, 0x4d, 0x8d, 0xbe, 0x2b, 0x51, 0x30, 0xbf, 0xc1, 0xd0, 0xd8, 0x3f, 0x51, 0x5e, 0x4f, 0xbf, + 0x99, 0xca, 0xf4, 0x3e, 0xe0, 0xe8, 0xb4, 0x3f, 0x5b, 0xf0, 0x31, 0xbf, 0x77, 0xed, 0x66, 0xbf, + 0x55, 0x9b, 0xc7, 0xbf, 0x05, 0xbc, 0x35, 0xbf, 0xed, 0x67, 0x6c, 0x3f, 0x9f, 0x4d, 0x7a, 0x3f, + 0x2e, 0x4e, 0x18, 0x3f, 0x19, 0x3f, 0x26, 0x3c, 0x74, 0x0a, 0x4d, 0xbf, 0x57, 0x10, 0x71, 0xbf, + 0xf0, 0x01, 0x7b, 0x3e, 0x38, 0x3a, 0xa6, 0xbf, 0x4e, 0x95, 0x9c, 0xbe, 0x6b, 0xcd, 0xad, 0x3e, + 0x54, 0xe2, 0x91, 0x3e, 0x3b, 0xef, 0x18, 0x3e, 0x63, 0x20, 0x5d, 0xbf, 0x68, 0xc6, 0xe4, 0xbe, + 0x4c, 0xee, 0x1c, 0x3f, 0x1e, 0xce, 0x5c, 0x3d, 0x0b, 0xd5, 0xc9, 0x3f, 0x49, 0x9e, 0x01, 0x3f, + 0x22, 0x5c, 0x91, 0xbe, 0x34, 0x9a, 0x86, 0x3f, 0x0a, 0xf1, 0x85, 0x3e, 0x75, 0xd2, 0x6b, 0x3f, + 0x13, 0x96, 0xcf, 0x3f, 0x43, 0xe1, 0x28, 0x3f, 0xa9, 0xb1, 0x78, 0xbf, 0xaa, 0x0d, 0x3a, 0xbf, + 0xfe, 0x86, 0x8b, 0x3f, 0x9e, 0x0a, 0x38, 0x3e, 0x69, 0x55, 0x9a, 0xbf, 0x6e, 0x3d, 0x57, 0xbf, + 0xb0, 0x75, 0x01, 0x40, 0x55, 0x6b, 0xfc, 0x3f, 0xde, 0xe8, 0xa1, 0xbf, 0x68, 0x05, 0x79, 0xbf, + 0xac, 0xe1, 0xc1, 0xbf, 0x99, 0x8c, 0x6f, 0x3f, 0x29, 0x8a, 0x18, 0xbe, 0xba, 0xa2, 0x88, 0x3e, + 0x9d, 0xc3, 0x3e, 0x3f, 0xea, 0x41, 0x13, 0xbf, 0x2f, 0xa6, 0xb9, 0xbf, 0xdf, 0x95, 0xda, 0x3e, + 0x2e, 0x29, 0x5f, 0xbf, 0x3d, 0x86, 0x9c, 0x3f, 0x4b, 0x6f, 0x4b, 0xbf, 0x15, 0xd1, 0x16, 0xbc, + 0x76, 0x39, 0xb7, 0x3f, 0xf1, 0x0e, 0x96, 0xbd, 0xa7, 0x55, 0xf1, 0x3a, 0x2c, 0x0e, 0xa3, 0x3e, + 0x1e, 0x94, 0x2b, 0x3f, 0x98, 0xf8, 0x4a, 0xbe, 0x95, 0x99, 0xc3, 0x3f, 0x99, 0x9b, 0xa8, 0xbf, + 0x08, 0xd0, 0x1b, 0xbf, 0x64, 0xeb, 0xfb, 0x3e, 0xb9, 0x2e, 0xc4, 0x3e, 0x9d, 0x41, 0xb1, 0xbf, + 0x51, 0xbd, 0xc0, 0x3f, 0x44, 0x15, 0x0f, 0xbf, 0x1a, 0xf1, 0x0f, 0xbf, 0xef, 0xa0, 0x1c, 0x40, + 0xdb, 0xdc, 0x50, 0xbf, 0xfe, 0x0a, 0x37, 0xbf, 0x96, 0xef, 0xe4, 0x3e, 0xdb, 0x5b, 0x97, 0x3e, + 0x8d, 0xcf, 0x96, 0xbf, 0x4f, 0xe8, 0xe3, 0x3f, 0x32, 0xd8, 0xe6, 0xbf, 0xe3, 0x1f, 0x9e, 0x3f, + 0x08, 0xeb, 0x6d, 0x3e, 0x2e, 0xf7, 0x9d, 0xbf, 0x03, 0x8e, 0x81, 0x3f, 0xa2, 0xdc, 0x80, 0xbf, + 0x7e, 0x21, 0x08, 0xbf, 0x4c, 0xa2, 0x5c, 0xbf, 0xec, 0xdd, 0x25, 0xbd, 0x22, 0xcd, 0x9a, 0xbf, + 0x4f, 0x87, 0x36, 0x3f, 0x43, 0xb9, 0x24, 0x3f, 0x76, 0x26, 0x47, 0xbf, 0xf0, 0xf3, 0xae, 0xbf, + 0x46, 0x25, 0xd3, 0xbe, 0x9a, 0x22, 0x0a, 0x3f, 0x01, 0x51, 0x94, 0xbf, 0x82, 0x37, 0xd7, 0xbe, + 0x18, 0xd0, 0xb4, 0x3f, 0x76, 0xf8, 0x0a, 0x3f, 0x6e, 0xd7, 0x98, 0xbf, 0xd5, 0x11, 0x86, 0xbf, + 0x0f, 0x31, 0xf3, 0xbd, 0xa7, 0x95, 0xe1, 0xbf, 0x9e, 0xab, 0x78, 0xbf, 0x89, 0xa5, 0xe2, 0xbe, + 0x9f, 0x09, 0xf5, 0xbe, 0xa1, 0x39, 0x52, 0x3f, 0x2f, 0x8c, 0x6b, 0x3f, 0xfd, 0x89, 0xaa, 0x3e, + 0xbd, 0x17, 0xb5, 0xbf, 0x5d, 0xff, 0x8a, 0xbd, 0xe9, 0x3f, 0x91, 0xbf, 0x0e, 0xe0, 0x11, 0x3d, + 0xca, 0x65, 0x0f, 0xc0, 0x30, 0xe9, 0x0f, 0xbf, 0xd7, 0x35, 0x85, 0x3f, 0xbe, 0x41, 0xba, 0xbf, + 0xdf, 0x3e, 0xf8, 0xbe, 0x6d, 0x2c, 0x35, 0x3f, 0x43, 0xa6, 0x11, 0x3f, 0x7d, 0x9d, 0x89, 0xbe, + 0x0f, 0xe2, 0xd8, 0x3f, 0x75, 0x3c, 0x01, 0x3f, 0xd4, 0x81, 0x90, 0x3f, 0x2e, 0x61, 0x87, 0x3f, + 0xba, 0x5c, 0x94, 0xbf, 0x1c, 0x46, 0x5f, 0x3f, 0xe2, 0x65, 0x07, 0xbf, 0xad, 0xbb, 0xa6, 0x3f, + 0x6e, 0xb7, 0x8d, 0xbf, 0x28, 0xef, 0x02, 0xbf, 0x02, 0x3f, 0x28, 0xbf, 0x15, 0xd6, 0x23, 0xbe, + 0x51, 0x9b, 0xd7, 0x3e, 0x56, 0x03, 0x95, 0x3f, 0xd7, 0x7f, 0x78, 0xbf, 0x42, 0x8c, 0x33, 0xbf, + 0x30, 0xc3, 0x31, 0x3f, 0x4c, 0xea, 0x7f, 0x3e, 0xd8, 0x64, 0xfa, 0xbe, 0x96, 0x70, 0xe4, 0xbe, + 0x95, 0xb8, 0x07, 0x3e, 0x48, 0xbd, 0xaa, 0xbc, 0x8f, 0x01, 0x4a, 0x3d, 0xa6, 0x79, 0x92, 0xbe, + 0xef, 0x6d, 0x55, 0x3f, 0x76, 0xdc, 0x5e, 0xbf, 0x93, 0x99, 0x9c, 0x3f, 0x2e, 0x6e, 0xa9, 0xbe, + 0x02, 0xae, 0x93, 0x3e, 0x33, 0xc9, 0xba, 0x3f, 0x63, 0x55, 0x76, 0xbf, 0x14, 0x02, 0xaa, 0x3e, + 0xd8, 0x72, 0x2e, 0x3c, 0xa1, 0xd3, 0x4f, 0x3e, 0x5c, 0xf8, 0x4c, 0xbf, 0xb2, 0xdf, 0x05, 0xbf, + 0xbf, 0x0e, 0x43, 0x3f, 0xdc, 0xc6, 0x65, 0x3f, 0x9b, 0x80, 0x5f, 0x3e, 0x3e, 0xca, 0x03, 0xc0, + 0xb1, 0x1d, 0xc9, 0xbf, 0x02, 0x59, 0x4e, 0x3e, 0x87, 0x94, 0x6c, 0x3d, 0xd1, 0x8e, 0x42, 0xbf, + 0x4e, 0xaa, 0xb0, 0xbf, 0x58, 0x1b, 0x40, 0x3d, 0xf9, 0x61, 0x95, 0x3f, 0x52, 0xd3, 0xc1, 0xbf, + 0xd4, 0x8e, 0x22, 0x3f, 0x10, 0x58, 0x2a, 0xbe, 0x36, 0xf0, 0xab, 0xbe, 0x0f, 0x12, 0x6a, 0xbf, + 0x12, 0xaa, 0x1d, 0x3f, 0xdf, 0x4c, 0x83, 0xbf, 0x43, 0xe7, 0x3b, 0x3e, 0x32, 0xb9, 0xc0, 0xbf, + 0x66, 0xac, 0x3d, 0x3f, 0x81, 0x4d, 0x56, 0x3f, 0x18, 0x26, 0x2a, 0xc0, 0x90, 0xe9, 0x53, 0x3e, + 0xcb, 0x52, 0x96, 0x3e, 0xb1, 0x32, 0x14, 0x3e, 0xa8, 0xcd, 0x88, 0xbf, 0x96, 0x64, 0x96, 0x3e, + 0x94, 0x44, 0xca, 0xbe, 0x85, 0xaf, 0x6e, 0xbe, 0x69, 0x20, 0x4c, 0x3f, 0xd6, 0x09, 0x0e, 0x3f, + 0xd8, 0x46, 0x44, 0x3e, 0x40, 0x42, 0x91, 0x3c, 0xa3, 0x78, 0x73, 0xbf, 0xc5, 0x38, 0x97, 0x3f, + 0x4d, 0xf4, 0x5e, 0xbf, 0x7a, 0x7f, 0x32, 0x3f, 0x5d, 0x33, 0x44, 0xbe, 0x92, 0x56, 0xa6, 0xbf, + 0xfa, 0xd7, 0x14, 0x3e, 0x18, 0xee, 0xb2, 0xbe, 0xc6, 0xb3, 0x2c, 0x3f, 0x15, 0x0d, 0xb0, 0xbf, + 0x48, 0x0a, 0x26, 0x3f, 0x72, 0x53, 0xcb, 0x3d, 0x24, 0x8e, 0x06, 0x40, 0xc8, 0xa7, 0xb2, 0xbf, + 0x6e, 0xf7, 0x30, 0x3f, 0x1f, 0x94, 0x1d, 0x40, 0x0b, 0xb4, 0x0d, 0x3e, 0xff, 0x64, 0x8a, 0xbf, + 0x4b, 0x55, 0x7b, 0xbe, 0x23, 0x00, 0xef, 0x3e, 0x33, 0xc1, 0x34, 0xbf, 0x97, 0x40, 0x81, 0xbf, + 0xc7, 0x1c, 0x9b, 0xbf, 0x66, 0xa5, 0x7c, 0xbe, 0x5b, 0xff, 0x99, 0x3e, 0xc3, 0x28, 0x6e, 0x3f, + 0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x59, 0xa7, 0xbf, 0x22, 0xdc, 0x95, 0x3f, 0x63, 0xff, 0xa3, 0xbf, + 0x02, 0x7a, 0x4d, 0x3f, 0x50, 0x1e, 0xd8, 0x3d, 0x50, 0xae, 0x37, 0xbd, 0xc2, 0xd7, 0x9b, 0xbf, + 0x10, 0x98, 0x01, 0x3f, 0xda, 0xa9, 0x1f, 0x3f, 0x16, 0x29, 0x7d, 0x3e, 0x31, 0x31, 0xa4, 0xbf, + 0x0e, 0xef, 0x25, 0x3f, 0x62, 0xa2, 0x9d, 0xbf, 0xdb, 0xfe, 0x07, 0xbf, 0xfb, 0x1e, 0x79, 0xbf, + 0x82, 0xf9, 0x63, 0x3e, 0x1f, 0x20, 0x9d, 0x3c, 0xd9, 0xaf, 0x02, 0xc0, 0xb6, 0x0a, 0xb7, 0xbf, + 0xc9, 0xb4, 0xc6, 0xbe, 0x5c, 0xf3, 0x5f, 0xbf, 0xcb, 0x62, 0x9a, 0x3f, 0xf4, 0xd0, 0x7f, 0x3f, + 0x74, 0x32, 0x76, 0x3f, 0x44, 0xf4, 0x03, 0xbf, 0xc4, 0x92, 0x1c, 0x3f, 0x38, 0xec, 0x28, 0x3f, + 0x38, 0x63, 0xd6, 0xbe, 0xe5, 0x29, 0x91, 0x3f, 0x03, 0x06, 0x8e, 0x3e, 0xb6, 0x98, 0xd4, 0x3f, + 0xc4, 0x99, 0x07, 0x3f, 0x6a, 0x20, 0xd5, 0x3f, 0x46, 0xed, 0x70, 0xbf, 0x83, 0xfc, 0xd2, 0xbf, + 0x8e, 0x91, 0x87, 0xbf, 0xce, 0xe2, 0x04, 0x3f, 0x1c, 0xc2, 0x14, 0xc0, 0x2c, 0x72, 0x92, 0x3f, + 0x98, 0x41, 0x55, 0x3e, 0x91, 0x83, 0x59, 0x3d, 0xb5, 0xd4, 0x0b, 0xbf, 0x77, 0x1c, 0xd8, 0x3f, + 0xca, 0x18, 0x96, 0x3f, 0x0f, 0x95, 0x7f, 0x3e, 0x1b, 0x8e, 0x22, 0xbf, 0xe4, 0x4e, 0xc2, 0x3f, + 0x1a, 0xe6, 0x77, 0x3f, 0x10, 0x28, 0x39, 0x3f, 0xb3, 0xf7, 0x01, 0x40, 0x77, 0x39, 0xb8, 0x3f, + 0x25, 0xfb, 0xfb, 0x3e, 0x66, 0x68, 0x29, 0x3e, 0x2d, 0x4d, 0xf6, 0xbf, 0x03, 0x46, 0xbb, 0x3e, + 0xab, 0xbd, 0x96, 0xbf, 0xd5, 0xcb, 0x69, 0xbf, 0x93, 0x9d, 0xd0, 0xbe, 0x43, 0x35, 0x26, 0xbe, + 0x05, 0x87, 0x47, 0xbf, 0xe5, 0xa5, 0xad, 0x3e, 0x15, 0xe1, 0x6b, 0x3f, 0x77, 0x79, 0xfa, 0x3d, + 0x6f, 0x68, 0x87, 0xbf, 0xec, 0x4d, 0x40, 0x3f, 0xb9, 0x26, 0x88, 0xbf, 0x22, 0x3b, 0x89, 0xbf, + 0x16, 0x31, 0x21, 0x3f, 0x89, 0x16, 0xba, 0x3d, 0xeb, 0x18, 0xec, 0xbe, 0x46, 0x5e, 0x14, 0x3e, + 0x53, 0xf8, 0x04, 0xbf, 0xec, 0xd2, 0x9e, 0x3e, 0x3c, 0xe6, 0xa1, 0x3f, 0xad, 0x41, 0x8f, 0x3f, + 0xb9, 0x4d, 0xba, 0x3f, 0x11, 0xba, 0x8b, 0x3f, 0xb1, 0x1d, 0xe0, 0xbe, 0xe7, 0xcd, 0x58, 0xbd, + 0xc4, 0x30, 0x09, 0x3f, 0x3b, 0x69, 0x9e, 0x3f, 0xcc, 0xcb, 0x1d, 0x3f, 0x16, 0x6e, 0x48, 0xbd, + 0x62, 0x5e, 0x36, 0xbf, 0xf9, 0x96, 0x0f, 0x40, 0xd0, 0x45, 0xad, 0xbe, 0xd3, 0x8a, 0x9e, 0x3f, + 0xc4, 0xf6, 0x33, 0xbf, 0xc1, 0x8b, 0x23, 0x3e, 0x4f, 0x3a, 0xfd, 0xbe, 0x64, 0x7a, 0x1b, 0x3f, + 0xdb, 0xfc, 0x9b, 0x3f, 0x02, 0x53, 0x99, 0xbf, 0x2c, 0x5a, 0x42, 0x3f, 0x33, 0x3c, 0xe1, 0x3f, + 0x14, 0xfd, 0xc4, 0xbf, 0xd3, 0x51, 0xb6, 0xbf, 0xb9, 0x42, 0x8d, 0x3e, 0xfb, 0xb2, 0x8e, 0xbe, + 0xde, 0x7b, 0x16, 0x3f, 0x1c, 0x4f, 0x81, 0xbf, 0xd7, 0xd1, 0x02, 0x3e, 0x97, 0xb5, 0xea, 0xbf, + 0xec, 0x38, 0x9b, 0xbf, 0xa7, 0xa5, 0x4b, 0xbf, 0xc1, 0x99, 0x37, 0x3f, 0xe1, 0x65, 0x07, 0x3e, + 0x79, 0x06, 0x25, 0x3e, 0xbc, 0xdd, 0xcc, 0x3e, 0x80, 0x5c, 0x57, 0xbf, 0xca, 0xe7, 0x99, 0x3f, + 0x4f, 0xe8, 0xab, 0xbe, 0x91, 0xd1, 0x01, 0xc0, 0xd6, 0xa2, 0xb7, 0x3e, 0x47, 0x15, 0x4e, 0x3f, + 0x65, 0x95, 0x38, 0x3f, 0xb6, 0xad, 0x8a, 0xbe, 0xb2, 0xad, 0x1c, 0xbd, 0x40, 0x00, 0x03, 0xbe, + 0x29, 0xce, 0x54, 0xbf, 0xe4, 0x75, 0xc6, 0xbf, 0xc0, 0x83, 0x9b, 0xbf, 0x12, 0xae, 0xa0, 0x3c, + 0xe7, 0x4e, 0xd3, 0x3e, 0xec, 0x81, 0xc7, 0xbf, 0x4e, 0x80, 0x8e, 0xbf, 0x59, 0x23, 0xa2, 0xbf, + 0x28, 0x02, 0xc6, 0x3f, 0x3a, 0x0f, 0xce, 0x3e, 0x02, 0x69, 0x63, 0x3f, 0x75, 0x8a, 0x36, 0x3d, + 0x24, 0xf4, 0x1c, 0x3f, 0xd8, 0xf1, 0xc6, 0x3f, 0x55, 0x23, 0x5f, 0x3e, 0x2b, 0xdf, 0x97, 0x3e, + 0xd3, 0x22, 0x18, 0xbd, 0x70, 0xf0, 0x8e, 0x3e, 0xe3, 0xdf, 0x7c, 0x3f, 0xac, 0x4a, 0x87, 0x3f, + 0x0e, 0x3f, 0x9e, 0x3e, 0xdd, 0x55, 0xfa, 0xbf, 0x63, 0x6f, 0x8f, 0xbf, 0xd0, 0x47, 0xe1, 0x3f, + 0x75, 0x93, 0x68, 0xbf, 0xd3, 0x42, 0x36, 0x3e, 0x48, 0xc7, 0x9d, 0x3d, 0x85, 0xfd, 0x63, 0xbf, + 0x50, 0x8e, 0xb2, 0xbf, 0x6a, 0xbf, 0xc6, 0x3e, 0x98, 0x4c, 0x7e, 0x3f, 0x27, 0x46, 0x5d, 0xbe, + 0xb3, 0x2b, 0xd3, 0x3f, 0xcc, 0x3d, 0xbf, 0x3f, 0x30, 0x9f, 0x5c, 0x3f, 0xf0, 0xc3, 0x67, 0xbe, + 0x70, 0xeb, 0xa7, 0xbf, 0x92, 0xd2, 0x74, 0xbe, 0xe9, 0x72, 0x9d, 0x3f, 0xf2, 0x42, 0x9e, 0xbf, + 0x90, 0x02, 0x2d, 0x3f, 0x91, 0xd4, 0x1e, 0xbf, 0x12, 0x95, 0x7f, 0xbd, 0xdf, 0x11, 0x7c, 0xbf, + 0x81, 0x01, 0xc7, 0x3e, 0xaf, 0x26, 0xe5, 0x3e, 0xfc, 0x9d, 0xcc, 0xbf, 0xa5, 0x0d, 0xe7, 0x3e, + 0xea, 0x46, 0xc3, 0x3e, 0x04, 0xca, 0x79, 0x3e, 0xb5, 0x30, 0x13, 0x3d, 0x3f, 0x6f, 0x5d, 0x3e, + 0x48, 0x73, 0x75, 0xbe, 0x1f, 0xb3, 0x35, 0x3e, 0xfd, 0xda, 0xc6, 0xbf, 0x4a, 0x6d, 0xc6, 0x3e, + 0xd5, 0x66, 0x99, 0x3e, 0x33, 0x05, 0xb3, 0x3f, 0x1b, 0x87, 0xd8, 0xbf, 0xc2, 0x9e, 0xfc, 0x3e, + 0xac, 0x0b, 0xff, 0xbe, 0x5d, 0x2a, 0x0b, 0xc0, 0xb3, 0xdb, 0x7b, 0xbf, 0x72, 0x63, 0x34, 0xbf, + 0x71, 0xca, 0x4e, 0x3f, 0x05, 0x80, 0x4c, 0x3e, 0x41, 0x39, 0x06, 0xbf, 0x41, 0x5e, 0x18, 0x3f, + 0x4e, 0x4a, 0xf2, 0xbf, 0xa7, 0xbf, 0xce, 0x3e, 0x33, 0x12, 0x49, 0x3f, 0x1e, 0xa3, 0x4f, 0xbe, + 0x5e, 0xd5, 0x3a, 0xbe, 0x6f, 0x82, 0x10, 0xbf, 0x87, 0xf2, 0x01, 0x40, 0x42, 0x1f, 0x93, 0xbf, + 0x6a, 0xc2, 0x02, 0x3f, 0xd8, 0x50, 0xd6, 0x3f, 0xf2, 0x80, 0x76, 0xbf, 0x8d, 0xc7, 0xb2, 0xbf, + 0xb3, 0xfc, 0x5b, 0x3f, 0x6d, 0x29, 0xb6, 0x3e, 0x48, 0x03, 0x2a, 0x3f, 0xc1, 0xa5, 0xb3, 0x3e, + 0x16, 0x3d, 0xa5, 0xbe, 0x47, 0xcc, 0x3e, 0xbf, 0x87, 0xca, 0x37, 0xbf, 0x3b, 0x6a, 0x61, 0x3e, + 0x69, 0x87, 0xad, 0x3f, 0x6a, 0x4e, 0xc1, 0xbf, 0xee, 0xa9, 0x5a, 0xbf, 0x65, 0x75, 0xa6, 0x3f, + 0x8d, 0x12, 0x24, 0xbd, 0x80, 0x25, 0x37, 0xc0, 0xbd, 0x92, 0xc4, 0x3f, 0x61, 0x0c, 0xf3, 0xbe, + 0xda, 0x3e, 0x0d, 0xbf, 0xc1, 0xc4, 0xb2, 0x3e, 0x41, 0xab, 0x02, 0x3f, 0x34, 0x7e, 0x54, 0xbf, + 0x96, 0xa0, 0x96, 0x3f, 0xb7, 0x1c, 0xb3, 0xbe, 0xdf, 0x95, 0xf7, 0x3e, 0x4a, 0x41, 0x7c, 0x3e, + 0xfb, 0xc3, 0x91, 0xbf, 0x55, 0x29, 0x9b, 0x3e, 0x91, 0x67, 0xb7, 0x3e, 0xdf, 0xb1, 0x62, 0xbf, + 0xe4, 0x83, 0x4c, 0xbf, 0x5e, 0x74, 0x37, 0x3f, 0x03, 0x60, 0x11, 0x3e, 0x70, 0x4e, 0xe0, 0x3d, + 0x9c, 0x75, 0x04, 0x40, 0x3a, 0x14, 0xc4, 0x3e, 0xe1, 0x10, 0x46, 0xbe, 0xfc, 0x11, 0xb4, 0x3e, + 0x8b, 0x9d, 0xbf, 0xbe, 0xaf, 0x19, 0xca, 0xbe, 0xc4, 0x91, 0x2a, 0x3f, 0x3d, 0xc5, 0x54, 0xbf, + 0xd3, 0x11, 0x02, 0x3e, 0x0c, 0xee, 0xbf, 0x3f, 0x69, 0xa4, 0x27, 0x40, 0x17, 0x7e, 0xfc, 0x3d, + 0xa8, 0xf7, 0x8b, 0xbf, 0x39, 0xa2, 0xbb, 0xbe, 0xb8, 0x70, 0x70, 0xbe, 0x9d, 0x3f, 0xdb, 0xbf, + 0x4f, 0x7b, 0x59, 0xbe, 0xa2, 0xcb, 0x75, 0xbd, 0x4b, 0xc8, 0x14, 0x3f, 0x93, 0x57, 0xd4, 0xbf, + 0xbd, 0x08, 0xa3, 0xbf, 0x2b, 0xe2, 0x5b, 0x3e, 0x0e, 0x60, 0x73, 0xbf, 0xee, 0xd4, 0xb8, 0x3d, + 0xa5, 0x6b, 0x05, 0x3f, 0x0e, 0x5c, 0xed, 0xbf, 0x6d, 0xc7, 0x1e, 0xbe, 0x86, 0x53, 0xb4, 0x3f, + 0x5b, 0xcd, 0xc3, 0xbd, 0xdc, 0x1e, 0x44, 0xbf, 0x74, 0xea, 0xfb, 0xbe, 0xb1, 0xef, 0xc8, 0xbf, + 0xeb, 0xa2, 0x93, 0xbf, 0x4f, 0x02, 0x91, 0xbf, 0xdd, 0x61, 0xb3, 0xbe, 0xc0, 0x4b, 0x4d, 0xbf, + 0x07, 0x74, 0x0c, 0xbe, 0x1b, 0x36, 0x4a, 0xbf, 0xc5, 0x5e, 0x62, 0x3f, 0x27, 0x31, 0x15, 0xc0, + 0x30, 0xb9, 0x99, 0xbf, 0x45, 0x24, 0x86, 0xbf, 0x26, 0x35, 0xaa, 0xbf, 0xbe, 0x58, 0x8c, 0xbe, + 0xfa, 0x29, 0x0f, 0xbf, 0x36, 0xb7, 0xef, 0xbf, 0xc1, 0x41, 0x35, 0xbf, 0x70, 0x1b, 0x75, 0x3d, + 0x5a, 0x2f, 0x93, 0xbf, 0xae, 0x3a, 0x20, 0x3e, 0x9d, 0x62, 0xeb, 0x3e, 0x93, 0xd3, 0x7c, 0xbe, + 0x7f, 0x83, 0xad, 0x3f, 0xfd, 0xe1, 0x10, 0xc0, 0xcb, 0x4b, 0xc7, 0x3f, 0xa2, 0x92, 0x27, 0x3f, + 0x98, 0x6c, 0xd0, 0xbf, 0x10, 0xd2, 0xf3, 0xbe, 0xc5, 0x2f, 0xa2, 0x3f, 0x76, 0x07, 0xd8, 0x3f, + 0xed, 0xf2, 0xff, 0x3e, 0xfd, 0x93, 0xa9, 0xbf, 0x73, 0xd1, 0x92, 0xbe, 0x22, 0x57, 0x5b, 0xbf, + 0x3e, 0xc9, 0xc8, 0xbf, 0x16, 0x7d, 0x21, 0x3e, 0x78, 0x6e, 0x7d, 0xbf, 0x3c, 0x7a, 0xf2, 0x3e, + 0x92, 0x17, 0xae, 0xbf, 0x8d, 0xbf, 0x01, 0x3e, 0x9d, 0xbf, 0x40, 0x3f, 0x18, 0x72, 0x59, 0x3f, + 0xb1, 0x87, 0xdb, 0x3f, 0xba, 0xfe, 0x83, 0x3f, 0x43, 0x33, 0x34, 0xc0, 0x8e, 0x34, 0x25, 0xbf, + 0x8d, 0x61, 0xba, 0xbe, 0x85, 0xc4, 0x3a, 0xbf, 0x03, 0x42, 0xde, 0x3e, 0xb6, 0x7d, 0xed, 0x3e, + 0x8d, 0xf1, 0xc3, 0x3f, 0x0f, 0xb7, 0x77, 0x3f, 0x30, 0xa5, 0x8e, 0xbe, 0xbd, 0x8b, 0xba, 0x3f, + 0xae, 0x85, 0x1b, 0x3f, 0x19, 0x8c, 0x87, 0xbf, 0xe0, 0x76, 0x4f, 0x3d, 0x7f, 0x60, 0x03, 0x3f, + 0xdc, 0xc4, 0x83, 0xbf, 0xe4, 0xf2, 0x64, 0x3e, 0x28, 0x56, 0x9b, 0x3f, 0x26, 0xe5, 0xa2, 0x3e, + 0x71, 0x6a, 0xd9, 0xbe, 0xb4, 0xc8, 0x09, 0x3f, 0x7e, 0x99, 0xcb, 0x3f, 0xf2, 0x3f, 0x9e, 0xbe, + 0x15, 0x37, 0x2d, 0xbf, 0x4b, 0xc3, 0x22, 0xbf, 0x1d, 0x45, 0xe8, 0x3e, 0xd6, 0x07, 0xe9, 0x3f, + 0xf6, 0x20, 0xe1, 0x3f, 0x42, 0xfe, 0xc4, 0x3d, 0xf6, 0x3f, 0xcf, 0xbf, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, + 0xe4, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, + 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +} // namespace neg_input_output_type_mismatch_svdf_kernel + +class NegTestDataInputOutputTypeMismatchSVDFKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchSVDFKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_svdf_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchSVDFKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_NEG_SVDF_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h b/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h new file mode 100644 index 00000000000..389b418eff2 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataSVDFBase : public TestDataBase +{ +public: + TestDataSVDFBase() = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + + const std::vector &get_input_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _input_data; + default: + assert(false && "Wrong input index"); + } + } + + const std::vector &get_output_data_by_index(int i) override final + { + assert(i == 0); + return _reference_output_data; + } + +protected: + std::vector _input_data; + std::vector _reference_output_data; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h b/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h new file mode 100644 index 00000000000..ad039655f0b --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TEST_MODELS_S8_UNPACK_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_UNPACK_KERNEL_H + +#include "TestDataUnpackBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace unpack_s8 +{ +/* + * Unpack Kernel: + * + * Input(2, 2, 2) + * | + * Unpack(num=2, axis=0) + * / \ + * Output1(2, 2, 2) Output1(2, 2, 2) + */ +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, + 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x14, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, + 0x00, 0x00, 0x00, 0x24, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x05, + 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x3a, 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, + 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, + 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x58, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, + 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00 + +}; +const std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8}; +const std::vector reference_output_data_1 = {1, 2, 3, 4}; +const std::vector reference_output_data_2 = {5, 6, 7, 8}; + +} // namespace unpack_s8 + +class TestDataS8Unpack : public TestDataUnpackBase +{ +public: + TestDataS8Unpack() + { + _input_data = unpack_s8::input_data; + _reference_output_data_1 = unpack_s8::reference_output_data_1; + _reference_output_data_2 = unpack_s8::reference_output_data_2; + _test_kernel_model_circle = unpack_s8::test_kernel_model_circle; + } + + ~TestDataS8Unpack() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_UNPACK_KERNEL_H diff --git a/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h b/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h new file mode 100644 index 00000000000..3b30b980b3f --- /dev/null +++ b/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H +#define ONERT_MICRO_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H + +#include "OMStatus.h" + +#include + +namespace onert_micro +{ +namespace train +{ +namespace losses_functions +{ + +// Cross Entropy +struct SparseCrossEntropy +{ + // Calculate sparse cross entropy error backpropagation between calculated and target data + static void calculateErrorBackpropagation(const uint32_t flat_size, const float *calculated_data, + const float *target_data, float *output_grad); +}; + +} // namespace losses_functions +} // namespace train +} // namespace onert_micro + +#endif // ONERT_MICRO_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H diff --git a/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h b/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h new file mode 100644 index 00000000000..64c73ae20ea --- /dev/null +++ b/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ONERT_MICRO_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H +#define ONERT_MICRO_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H + +#include "OMStatus.h" + +#include + +namespace onert_micro +{ +namespace train +{ +namespace metrics +{ + +// Accuracy metric +struct SparseCrossEntropyAccuracy +{ + // Calculate accuracy metric between calculated and target data + static float calculateValue(const uint32_t flat_size, const float *calculated_data, + const float *target_data); +}; + +} // namespace metrics +} // namespace train +} // namespace onert_micro + +#endif // ONERT_MICRO_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H diff --git a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp index 24535625a02..e13fd110b58 100644 --- a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp +++ b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp @@ -19,10 +19,12 @@ #include "core/train/OMTrainingHandler.h" #include "train/losses_functions/MSE.h" #include "train/losses_functions/CrossEntropy.h" +#include "train/losses_functions/SparseCrossEntropy.h" #include "train/metrics/MSE.h" #include "train/metrics/CrossEntropy.h" #include "train/metrics/Accuracy.h" #include "train/metrics/MAE.h" +#include "train/metrics/SparseCrossEntropyAccuracy.h" using namespace onert_micro::core::train; using namespace onert_micro::core; @@ -56,11 +58,18 @@ OMStatus OMTrainingHandler::handleError(const OMConfig &config, OMRuntimeStorage OMStatus status = forward_storage.getDataByTensorIndex(&calculated_data, forward_output_index); assert(calculated_data != nullptr); + OMLoss loss_type = config.training_context.loss; + // Get target data auto data_type_size = sizeof(core::OMDataType(forward_output_tensor->type())); size_t offset = batch_num * data_type_size * flat_size; + + // Need to check loss type to control proper offset. + if (loss_type == SPARSE_CROSS_ENTROPY) + { + offset = batch_num * data_type_size; + } uint8_t *target_data = _training_storage.getTargetData(i) + offset; - OMLoss loss_type = config.training_context.loss; // Allocate data for error gradient for current calculated data and target data uint8_t *output_grad_data; @@ -85,6 +94,13 @@ OMStatus OMTrainingHandler::handleError(const OMConfig &config, OMRuntimeStorage reinterpret_cast(target_data), reinterpret_cast(output_grad_data)); break; } + case SPARSE_CROSS_ENTROPY: + { + losses_functions::SparseCrossEntropy::calculateErrorBackpropagation( + flat_size, reinterpret_cast(calculated_data), + reinterpret_cast(target_data), reinterpret_cast(output_grad_data)); + break; + } default: { assert(false && "Unsupported loss type"); @@ -222,6 +238,12 @@ OMStatus OMTrainingHandler::evaluateMetric(OMMetrics metric, void *metric_val, assert(calculated_data != nullptr); // Get target data + /** NOTE: + * This offset will always return 0 if the MODEL OUTPUT is returning 1 value of prediction. + * (forward_output->size() == length of output vector.) + * one-hot: size == target_numbers + * Sparse cross : size == 1 + */ size_t offset = batch_num * sizeof(core::OMDataType(forward_output_tensor->type())) * flat_size; uint8_t *target_data = _training_storage.getTargetData(i) + offset; @@ -261,6 +283,14 @@ OMStatus OMTrainingHandler::evaluateMetric(OMMetrics metric, void *metric_val, reinterpret_cast(target_data)); break; } + case SPARSE_CROSS_ENTROPY_ACCURACY: + { + // Note: sum up new calculated value for current sample + *f_metric_val += metrics::SparseCrossEntropyAccuracy::calculateValue( + flat_size, reinterpret_cast(calculated_data), + reinterpret_cast(target_data)); + break; + } default: { assert(false && "Unsupported loss type"); diff --git a/onert-micro/onert-micro/src/execute/kernels/Less.cpp b/onert-micro/onert-micro/src/execute/kernels/Less.cpp index 6d27f66abd3..b815849cf6f 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Less.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Less.cpp @@ -73,7 +73,12 @@ OMStatus onert_micro::execute::execute_kernel_CircleLess(const OMExecuteArgs &ex break; #ifndef DIS_QUANT case circle::TensorType_UINT8: - evalQuantizedComparisonGeneric(&runtime_kernel, onert_micro::execute::pal::LessFn); + evalQuantizedComparisonGeneric(&runtime_kernel, + onert_micro::execute::pal::LessFn); + break; + case circle::TensorType_INT8: + evalQuantizedComparisonGeneric(&runtime_kernel, + onert_micro::execute::pal::LessFn); break; #endif // DIS_QUANT diff --git a/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp b/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp new file mode 100644 index 00000000000..3e6301e7628 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "execute/OMKernelExecutionBuilder.h" +#include "OMStatus.h" +#include "execute/OMRuntimeKernel.h" +#include "core/OMUtils.h" +#include "core/OMRuntimeShape.h" + +#include "PALQuantize.h" + +using namespace onert_micro; +using namespace onert_micro::execute; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +// NOTE: doesnt currently support dynamic shapes +OMStatus onert_micro::execute::execute_kernel_CircleQuantize(const OMExecuteArgs &execute_args) +{ + core::OMRuntimeContext &runtime_context = execute_args.runtime_context; + core::OMRuntimeStorage &runtime_storage = execute_args.runtime_storage; + uint16_t op_index = execute_args.kernel_index; + + const circle::Tensor *input = nullptr; + const circle::Tensor *output = nullptr; + + uint8_t *input_data = nullptr; + uint8_t *output_data = nullptr; + + OMStatus status = Ok; + + { + OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + input = runtime_kernel.inputs[inputTensorIdx]; + output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + output_data = runtime_kernel.outputs_data[outputTensorIdx]; + } + + assert(input_data != nullptr); + assert(output_data != nullptr); + + assert(input->type() == circle::TensorType_FLOAT32); + + switch (output->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_INT8: + { + assert(output->quantization() != nullptr); + assert(output->quantization()->scale() != nullptr and + output->quantization()->scale()->size() == 1); + assert(output->quantization()->zero_point() != nullptr and + output->quantization()->zero_point()->size() == 1); + core::QuantizationParams params{}; + params.zero_point = output->quantization()->zero_point()->operator[](0); + params.scale = output->quantization()->scale()->operator[](0); + + status = pal::Quantize(params, core::OMRuntimeShape(input).flatSize(), + core::utils::castInputData(input_data), + core::utils::castOutputData(output_data)); + } + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedType; + assert(false && "Unsupported type."); + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp b/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp new file mode 100644 index 00000000000..418a6b155d1 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OMStatus.h" + +#include "core/OMUtils.h" +#include "core/OMDataType.h" +#include "core/OMKernelData.h" +#include "core/memory/OMMemoryManager.h" + +#include "execute/OMKernelExecutionBuilder.h" +#include "execute/OMRuntimeKernel.h" + +#include "PALSVDF.h" + +using namespace onert_micro; +using namespace onert_micro::core; +using namespace onert_micro::execute; + +namespace +{ + +constexpr int inputTensorIdx = 0; +constexpr int weightsFeatureTensorIdx = 1; +constexpr int weightsTimeTensorIdx = 2; +constexpr int biasTensorIdx = 3; +constexpr int inputActivationStateTensorIdx = + 4; // This is a variable tensor, and will be modified by this op. +constexpr int outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::execute::execute_kernel_CircleSVDF(const OMExecuteArgs &execute_args) +{ + core::OMRuntimeContext &runtime_context = execute_args.runtime_context; + core::OMRuntimeStorage &runtime_storage = execute_args.runtime_storage; + uint16_t op_index = execute_args.kernel_index; + + const circle::Tensor *input; + const circle::Tensor *weights_feature; + const circle::Tensor *weights_time; + const circle::Tensor *bias; + const circle::Tensor *activation_state; + + const circle::Tensor *output; + + uint8_t *input_data; + uint8_t *weights_feature_data; + uint8_t *weights_time_data; + uint8_t *bias_data; + uint8_t *activation_state_data; + uint8_t *output_data; + const circle::SVDFOptions *options = nullptr; + // Read kernel + { + execute::OMRuntimeKernel runtime_kernel; + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + input = runtime_kernel.inputs[inputTensorIdx]; + weights_feature = runtime_kernel.inputs[weightsFeatureTensorIdx]; + weights_time = runtime_kernel.inputs[weightsTimeTensorIdx]; + bias = runtime_kernel.inputs[biasTensorIdx]; + activation_state = runtime_kernel.inputs[inputActivationStateTensorIdx]; + + output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(weights_feature != nullptr); + assert(weights_time != nullptr); + // bias can be nullptr + assert(activation_state != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + weights_feature_data = runtime_kernel.inputs_data[weightsFeatureTensorIdx]; + weights_time_data = runtime_kernel.inputs_data[weightsTimeTensorIdx]; + bias_data = runtime_kernel.inputs_data[biasTensorIdx]; + activation_state_data = runtime_kernel.inputs_data[inputActivationStateTensorIdx]; + output_data = runtime_kernel.outputs_data[outputTensorIdx]; + + assert(input_data != nullptr); + assert(weights_feature_data != nullptr); + assert(weights_time_data != nullptr); + // bias can be nullptr + assert(output_data != nullptr); + + options = runtime_kernel.first_operator->builtin_options_as_SVDFOptions(); + } + + OMStatus status; + OMRuntimeShape input_shape(input); + OMRuntimeShape weights_feature_shape(weights_feature); + OMRuntimeShape weights_time_shape(weights_time); + OMRuntimeShape activation_state_shape(activation_state); + OMRuntimeShape output_shape(output); + + // Define input constants based on input tensor definition above: + const int rank = options->rank(); + const int input_size = input_shape.dims(1); + const int batch_size = input_shape.dims(0); + const int num_filters = weights_feature_shape.dims(0); + + const int num_units = num_filters / rank; + const int memory_size = weights_time_shape.dims(1); + + const auto activation_state_size = + activation_state_shape.flatSize() * sizeof(core::OMDataType(output->type())); + status = + core::memory::OMMemoryManager::allocateMemory(activation_state_size, &activation_state_data); + if (status != Ok) + return status; + + std::memset(activation_state_data, 0, activation_state_size); + // Temporary buffer + uint8_t *scratch_buffer; + status = core::memory::OMMemoryManager::allocateMemory( + batch_size * num_filters * sizeof(core::OMDataType(output->type())), &scratch_buffer); + + assert(status == Ok); + if (status != Ok) + return status; + + switch (input->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_FLOAT32: + { + status = pal::SVDF( + utils::castInputData(input_data), utils::castInputData(weights_feature_data), + utils::castInputData(weights_time_data), utils::castInputData(bias_data), + utils::castOutputData(activation_state_data), + utils::castOutputData(scratch_buffer), utils::castOutputData(output_data), + rank, input_size, batch_size, num_filters, num_units, memory_size, + options->fused_activation_function()); + } + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedActivation; + assert(false && "Unsupported type."); + break; + } + } + + status = core::memory::OMMemoryManager::deallocateMemory(activation_state_data); + status = core::memory::OMMemoryManager::deallocateMemory(scratch_buffer); + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp b/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp index 313b80febf7..9eef7a22f61 100644 --- a/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp @@ -77,6 +77,15 @@ OMStatus onert_micro::execute::execute_kernel_CircleSpaceToDepth( } break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + { + status = + pal::SpaceToDepth(block_size, input_shape, reinterpret_cast(input_data), + output_shape, reinterpret_cast(output_data)); + } + break; +#endif // DIS_QUANT default: { status = UnsupportedType; diff --git a/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp b/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp new file mode 100644 index 00000000000..c3da0afeb35 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OMStatus.h" + +#include "core/OMUtils.h" +#include "core/OMKernelData.h" + +#include "execute/OMKernelExecutionBuilder.h" +#include "execute/OMUtils.h" +#include "execute/OMRuntimeKernel.h" + +#include "PALSplit.h" + +using namespace onert_micro; +using namespace onert_micro::core; +using namespace onert_micro::execute; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t axisTensorIdx = 2; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::execute::execute_kernel_CircleSplitV(const OMExecuteArgs &execute_args) +{ + core::OMRuntimeContext &runtime_context = execute_args.runtime_context; + core::OMRuntimeStorage &runtime_storage = execute_args.runtime_storage; + uint16_t op_index = execute_args.kernel_index; + + const circle::Tensor *input; + const circle::Tensor *axis; + const circle::Tensor *output; + + uint8_t *input_data; + uint8_t *axis_data; + + // Read kernel + core::SplitParams params{}; + { + execute::OMRuntimeKernel runtime_kernel; + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + input = runtime_kernel.inputs[inputTensorIdx]; + axis = runtime_kernel.inputs[axisTensorIdx]; + output = runtime_kernel.outputs[outputTensorIdx]; + assert(input != nullptr); + assert(axis != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + axis_data = runtime_kernel.inputs_data[axisTensorIdx]; + assert(input_data != nullptr); + assert(axis_data != nullptr); + + params.num_outputs = runtime_kernel.outputs_num; + + for (uint32_t i = 0; i < params.num_outputs; ++i) + { + params.output_data[i] = runtime_kernel.outputs_data[i]; + } + } + OMStatus status; + OMRuntimeShape axis_shape(axis); + OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); + + int32_t axis_value = axis_data[0]; + if (axis_value < 0) + { + axis_value += input_shape.dimensionsCount() + 1; + } + + switch (input->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_FLOAT32: + status = pal::Split(params, input_shape, core::utils::castInputData(input_data), + output_shape, axis_value); + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedActivation; + assert(false && "Unsupported type."); + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/Sub.cpp b/onert-micro/onert-micro/src/execute/kernels/Sub.cpp index 6e32e88f3b2..788eb6813e0 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Sub.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Sub.cpp @@ -38,6 +38,50 @@ constexpr uint32_t input1TensorIdx = 0; constexpr uint32_t input2TensorIdx = 1; constexpr uint32_t outputTensorIdx = 0; +void calculateQuantParams(core::ArithmeticQuantParams ¶ms, const circle::Tensor *input1, + const circle::Tensor *input2, const circle::Tensor *output, + circle::ActivationFunctionType act) +{ + long input1_zp; + long input2_zp; + long output_zp; + + float input1_scale; + float input2_scale; + float output_scale; + + // Read input1 quant params + readQuantParams(input1, input1_zp, input1_scale); + // Read input2 quant params + readQuantParams(input2, input2_zp, input2_scale); + // Read output quant params + readQuantParams(output, output_zp, output_scale); + + params.input1_offset = -static_cast(input1_zp); + params.input2_offset = -static_cast(input2_zp); + params.output_offset = static_cast(output_zp); + params.left_shift = (output->type() == circle::TensorType_INT16) ? 15 : 20; + const double twice_max_input_scale = + 2 * static_cast(std::max(input1_scale, input2_scale)); + const double real_input1_multiplier = static_cast(input1_scale) / twice_max_input_scale; + const double real_input2_multiplier = static_cast(input2_scale) / twice_max_input_scale; + const double real_output_multiplier = + twice_max_input_scale / ((1 << params.left_shift) * static_cast(output_scale)); + + quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, ¶ms.input1_multiplier, + ¶ms.input1_shift); + + quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, ¶ms.input2_multiplier, + ¶ms.input2_shift); + + quantizeMultiplierSmallerThanOneExp(real_output_multiplier, ¶ms.output_multiplier, + ¶ms.output_shift); + + calculateActivationRangeQuantized(act, output_zp, output_scale, output->type(), + ¶ms.quantized_activation_min, + ¶ms.quantized_activation_max); +} + } // namespace // NOTE: doesnt currently support dynamic shapes @@ -160,6 +204,31 @@ OMStatus onert_micro::execute::execute_kernel_CircleSub(const OMExecuteArgs &exe } break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + { + core::ArithmeticQuantParams sub_params{}; + + calculateQuantParams(sub_params, input1, input2, output, + options->fused_activation_function()); + + if (need_broadcast) + { + status = pal::BroadcastSub4DSlow( + sub_params, input1_shape, core::utils::castInputData(input1_data), input2_shape, + core::utils::castInputData(input2_data), output_shape, + core::utils::castOutputData(output_data)); + } + else + { + status = pal::Sub(sub_params, input1_shape.flatSize(), + core::utils::castInputData(input1_data), + core::utils::castInputData(input2_data), + core::utils::castOutputData(output_data)); + } + } + break; +#endif // DIF_QUANT default: { status = UnsupportedType; diff --git a/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp b/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp index cfa61f4b537..ecb0b01e721 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp @@ -93,6 +93,13 @@ OMStatus onert_micro::execute::execute_kernel_CircleUnpack(const OMExecuteArgs & output_shape, axis_value); break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + status = + pal::Unpack(params, input_shape, core::utils::castInputData(input_data), + output_shape, axis_value); + break; +#endif // DIS_QUANT default: { status = UnsupportedActivation; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp index 0d142568d53..bcf99ec2c40 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp @@ -18,6 +18,7 @@ #include "test_models/concatenation/FloatConcatenationKernel.h" #include "test_models/concatenation/NegConcatenationKernel.h" #include "test_models/concatenation/IntConcatenationKernel.h" +#include "test_models/concatenation/S8ConcatenationKernel.h" namespace onert_micro { @@ -33,6 +34,14 @@ class ConcatenationTest : public ::testing::Test // Do nothing }; +TEST_F(ConcatenationTest, S8_P) +{ + test_model::TestDataS8Concatenation test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(ConcatenationTest, INT64_P) { test_model::TestDataS64Concatenation test_data_kernel; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp index b3a47d4f9e6..bb256cd360a 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp @@ -17,6 +17,7 @@ #include "execute/OMTestUtils.h" #include "test_models/gather/FloatGatherKernel.h" #include "test_models/gather/IntGatherKernel.h" +#include "test_models/gather/S8GatherKernel.h" #include "test_models/gather/NegGatherKernel.h" namespace onert_micro @@ -49,6 +50,14 @@ TEST_F(GatherTest, Gather_Int_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(GatherTest, Gather_S8_P) +{ + onert_micro::test_model::TestDataS8Gather test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(GatherTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchGatherKernel test_data_kernel; @@ -63,6 +72,13 @@ TEST_F(GatherTest, Wrong_position_type_NEG) EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); } +TEST_F(GatherTest, Wrong_scale_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputScaleMismatchGatherKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + TEST_F(GatherTest, Wrong_axis_NEG) { onert_micro::test_model::NegTestDataWrongAxisGatherKernel test_data_kernel; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp index f7b8b8f08bb..61aa5419c8d 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp @@ -19,6 +19,7 @@ #include "test_models/less/FloatLessKernel.h" #include "test_models/less/IntLessKernel.h" #include "test_models/less/QuantLessKernel.h" +#include "test_models/less/S8LessKernel.h" #include "test_models/less/NegTestDataLessKernel.h" namespace onert_micro @@ -124,6 +125,26 @@ TEST_F(LessTest, Quant_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(LessTest, S8_P) +{ + const bool is_with_broadcast = false; + onert_micro::test_model::TestDataS8Less test_data_kernel(is_with_broadcast, false); + + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(LessTest, S8_NEG) +{ + const bool is_with_broadcast = false; + onert_micro::test_model::TestDataS8Less test_data_kernel(is_with_broadcast, true); + + EXPECT_DEATH((onert_micro::execute::testing::checkKernel(2, &test_data_kernel)), + ""); +} + TEST_F(LessTest, Quant_NEG) { const bool is_with_broadcast = false; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp index 9b82cadae50..60d2efca403 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/logistic/FloatLogisticKernel.h" +#include "test_models/logistic/S8LogisticKernel.h" #include "test_models/logistic/NegLogisticKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(LogisticTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(LogisticTest, S8_P) +{ + onert_micro::test_model::TestDataS8Logistic test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(LogisticTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchLogisticKernel test_data_kernel; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp index 1f63ea31794..57a8fbd8d6a 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp @@ -47,6 +47,14 @@ TEST_F(PackTest, Int_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(PackTest, S8_P) +{ + test_model::TestDataS8Pack test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + // TODO: add negative tests and quant version } // namespace testing diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp new file mode 100644 index 00000000000..b991d3e6cc8 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "execute/OMTestUtils.h" +#include "test_models/quantize/FloatQuantizeKernel.h" +#include "test_models/quantize/NegQuantizeKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class QuantizeTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(QuantizeTest, Float_P) +{ + onert_micro::test_model::TestDataFloatQuantize test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(QuantizeTest, Invalid_output_shape_NEG) +{ + onert_micro::test_model::NegTestDataWithInvalidOutputShapeQuantizeKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp index dda748e54b3..873a6c18d36 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp @@ -39,6 +39,20 @@ TEST_F(ReshapeTest, MainTest_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(ReshapeTest, S8_P) +{ + onert_micro::test_model::TestDataS8ReshapeKernel test_data_kernel(false); + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(ReshapeTest, UNMATCHED_IOTYPE_NEG) +{ + onert_micro::test_model::TestDataS8ReshapeKernel test_data_kernel(true); + EXPECT_DEATH(checkKernel(1, &test_data_kernel), ""); +} + TEST_F(ReshapeTest, MainTest_NEG) { onert_micro::test_model::TestDataReshapeKernel test_data_kernel(true); diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp new file mode 100644 index 00000000000..049cab7cda5 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "execute/OMTestUtils.h" +#include "test_models/svdf/FloatSVDFKernel.h" +#include "test_models/svdf/NegSVDFKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class SVDFTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(SVDFTest, Float_P) +{ + onert_micro::test_model::TestDataFloatSVDF test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, + FloatArrayNear(test_data_kernel.get_output_data_by_index(0), 0.0001f)); +} + +TEST_F(SVDFTest, Input_output_type_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputTypeMismatchSVDFKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp index e427e2068a5..f9c55e2d836 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/space_to_depth/FloatSpaceToDepthKernel.h" +#include "test_models/space_to_depth/S8SpaceToDepthKernel.h" #include "test_models/space_to_depth/NegSpaceToDepthKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(SpaceToDepthTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(SpaceToDepthTest, S8_P) +{ + onert_micro::test_model::TestDataS8SpaceToDepth test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(SpaceToDepthTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchSpaceToDepthKernel test_data_kernel; @@ -47,6 +56,13 @@ TEST_F(SpaceToDepthTest, Input_output_type_mismatch_NEG) EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); } +TEST_F(SpaceToDepthTest, Input_output_shape_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputShapeMismatchSpaceToDepthKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + } // namespace testing } // namespace execute } // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp new file mode 100644 index 00000000000..153d1371717 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "execute/OMTestUtils.h" +#include "test_models/split_v/FloatSplitVKernel.h" +#include "test_models/split_v/NegSplitVKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class SplitVTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(SplitVTest, Float_P) +{ + onert_micro::test_model::TestDataFloatSplitV test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(SplitVTest, Input_output_type_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputTypeMismatchSplitVKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp index 91d9da48a75..56b361d7f30 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp @@ -18,6 +18,7 @@ #include "test_models/sub/FloatSubKernel.h" #include "test_models/sub/NegSubKernel.h" #include "test_models/sub/IntSubKernel.h" +#include "test_models/sub/S8SubKernel.h" namespace onert_micro { @@ -53,6 +54,18 @@ TEST_F(SubTest, INT_P) } } +TEST_F(SubTest, S8_P) +{ + // No broadcast + { + const bool is_with_broadcast = false; + test_model::TestDataS8Sub test_data_add_no_broadcasting(is_with_broadcast); + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_add_no_broadcasting); + EXPECT_THAT(output_data_vector, test_data_add_no_broadcasting.get_output_data_by_index(0)); + } +} + TEST_F(SubTest, Float_P) { // No broadcast diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp index 9c5738842a5..d0c76113ce5 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/unpack/FloatUnpackKernel.h" +#include "test_models/unpack/S8UnpackKernel.h" #include "test_models/unpack/NegUnpackKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(UnpackTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(UnpackTest, S8_P) +{ + onert_micro::test_model::TestDataS8Unpack test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(UnpackTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchUnpackKernel test_data_kernel; diff --git a/onert-micro/onert-micro/src/import/kernels/Gather.cpp b/onert-micro/onert-micro/src/import/kernels/Gather.cpp index 622c700ddb4..709b59b38f8 100644 --- a/onert-micro/onert-micro/src/import/kernels/Gather.cpp +++ b/onert-micro/onert-micro/src/import/kernels/Gather.cpp @@ -71,6 +71,20 @@ OMStatus onert_micro::import::configure_kernel_CircleGather(const OMConfigureArg if (status != Ok) return status; +#ifndef DIS_QUANT + if (input_type == circle::TensorType_INT8) + { + status = utils::checkCondition(*output->quantization()->scale()->begin() == + *input->quantization()->scale()->begin()); + if (status != Ok) + return status; + status = utils::checkCondition(*output->quantization()->zero_point()->begin() == + *input->quantization()->zero_point()->begin()); + if (status != Ok) + return status; + } +#endif // DIS_QUANT + int32_t axis = options->axis(); core::OMRuntimeShape input_shape(input); diff --git a/onert-micro/onert-micro/src/import/kernels/Quantize.cpp b/onert-micro/onert-micro/src/import/kernels/Quantize.cpp new file mode 100644 index 00000000000..bf2750c75c6 --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/Quantize.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "import/OMKernelConfigureBuilder.h" +#include "core/OMUtils.h" +#include "OMStatus.h" +#include "execute/OMRuntimeKernel.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleQuantize(const OMConfigureArgs &config_args) +{ + OMRuntimeContext &runtime_context = config_args.runtime_context; + uint16_t op_index = config_args.kernel_index; + + onert_micro::execute::OMRuntimeKernel runtime_kernel; + + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(output != nullptr); + + OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); + + // Check shapes + status = utils::checkCondition(input_shape == output_shape); + if (status != Ok) + return status; + + // Check input type is float + status = utils::checkCondition(input->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + + // Check output quantization params + const auto *output_quantization = output->quantization(); + status = utils::checkCondition(output->type() != circle::TensorType_FLOAT32 or + output_quantization != nullptr and + output_quantization->scale() != nullptr and + output_quantization->scale()->size() == 1); + if (status != Ok) + return status; + + return status; +} diff --git a/onert-micro/onert-micro/src/import/kernels/SVDF.cpp b/onert-micro/onert-micro/src/import/kernels/SVDF.cpp new file mode 100644 index 00000000000..25506b4743f --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/SVDF.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OMStatus.h" + +#include "core/OMUtils.h" +#include "core/OMKernelData.h" + +#include "import/OMKernelConfigureBuilder.h" + +#include "execute/OMRuntimeKernel.h" +#include "execute/OMUtils.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr int inputTensorIdx = 0; +constexpr int weightsFeatureTensorIdx = 1; +constexpr int weightsTimeTensorIdx = 2; +constexpr int biasTensorIdx = 3; +constexpr int inputActivationStateTensorIdx = + 4; // This is a variable tensor, and will be modified by this op. +constexpr int outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleSVDF(const OMConfigureArgs &config_args) +{ + // Validate Tensor Inputs (dtype depends on quantization): + // [0] = Input, {2, batch_size, input_size} + // [1] = Weights Feature, {2, num_filters, input_size} + // [2] = Weights Time, {2, num_filters, memory_size} + // [3] = Bias (optional), {1, num_units} + // [4] = Activation State (variable), {2, batch_size, memory_size * num_filters} + + OMRuntimeContext &runtime_context = config_args.runtime_context; + uint16_t op_index = config_args.kernel_index; + + execute::OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *weights_feature = runtime_kernel.inputs[weightsFeatureTensorIdx]; + const circle::Tensor *weights_time = runtime_kernel.inputs[weightsTimeTensorIdx]; + const circle::Tensor *bias = runtime_kernel.inputs[biasTensorIdx]; + const circle::Tensor *activation_state = runtime_kernel.inputs[inputActivationStateTensorIdx]; + + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(weights_feature != nullptr); + assert(weights_time != nullptr); + // bias can be nullptr + assert(activation_state != nullptr); + assert(output != nullptr); + + OMStatus status = Ok; + + if (status != Ok) + return status; + + const auto *options = runtime_kernel.first_operator->builtin_options_as_SVDFOptions(); + status = utils::checkCondition(options != nullptr); + if (status != Ok) + return status; + + OMRuntimeShape input_shape(input); + OMRuntimeShape weights_feature_shape(weights_feature); + OMRuntimeShape weights_time_shape(weights_time); + OMRuntimeShape activation_state_shape(activation_state); + OMRuntimeShape output_shape(output); + + // Define input constants based on input tensor definition above: + const int rank = options->rank(); + const int input_size = input_shape.dims(1); + const int batch_size = input_shape.dims(0); + const int num_filters = weights_feature_shape.dims(0); + status = utils::checkCondition(num_filters % rank == 0); + if (status != Ok) + return status; + + const int num_units = num_filters / rank; + const int memory_size = weights_time_shape.dims(1); + + status = utils::checkCondition(input_shape.dimensionsCount() == 2); + if (status != Ok) + return status; + // Validate Tensor Output: + // [0] = float/int8_t, {2, batch_size, num_units} + status = + utils::checkCondition(output_shape.dimensionsCount() == 2 and + output_shape.dims(0) == batch_size and output_shape.dims(1) == num_units); + if (status != Ok) + return status; + + // Validate Weights Feature Input Tensor + status = utils::checkCondition(weights_feature_shape.dimensionsCount() == 2 and + weights_feature_shape.dims(1) == input_size); + if (status != Ok) + return status; + + // Validate Weights Time Input Tensor: + status = utils::checkCondition(weights_time_shape.dimensionsCount() == 2 and + weights_time_shape.dims(0) == num_filters and + weights_time_shape.dims(1) == memory_size); + if (status != Ok) + return status; + + // Validate Optional Bias Input Tensor: + if (bias != nullptr) + { + status = utils::checkCondition(OMRuntimeShape(bias).dims(0) == num_units); + if (status != Ok) + return status; + } + + // Validate Activation State Input Tensor: + status = utils::checkCondition(activation_state_shape.dimensionsCount() == 2 and + activation_state_shape.dims(0) == batch_size and + activation_state_shape.dims(1) == memory_size * num_filters); + if (status != Ok) + return status; + + if (input->type() == circle::TensorType_FLOAT32) + { + status = utils::checkCondition(weights_feature->type() == circle::TensorType_FLOAT32 and + weights_time->type() == circle::TensorType_FLOAT32 and + activation_state->type() == circle::TensorType_FLOAT32 and + output->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + if (bias) + { + status = utils::checkCondition(bias->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp b/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp index 8520ccf5de4..b8843293b9b 100644 --- a/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp +++ b/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp @@ -53,6 +53,7 @@ OMStatus onert_micro::import::configure_kernel_CircleSpaceToDepth( return status; OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); const auto *options = runtime_kernel.first_operator->builtin_options_as_SpaceToDepthOptions(); const int32_t block_size = options->block_size(); @@ -66,8 +67,8 @@ OMStatus onert_micro::import::configure_kernel_CircleSpaceToDepth( const int input_height = input_shape.dims(kHeightRank); const int input_width = input_shape.dims(kWidthRank); - int output_height = input_height / block_size; - int output_width = input_width / block_size; + int output_height = output_shape.dims(kHeightRank); + int output_width = output_shape.dims(kWidthRank); status = utils::checkCondition(input_height == output_height * block_size); if (status != Ok) diff --git a/onert-micro/onert-micro/src/import/kernels/SplitV.cpp b/onert-micro/onert-micro/src/import/kernels/SplitV.cpp new file mode 100644 index 00000000000..44854b8c2e8 --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/SplitV.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OMStatus.h" + +#include "core/OMUtils.h" +#include "import/OMKernelConfigureBuilder.h" +#include "execute/OMRuntimeKernel.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t sizeTensorIdx = 1; +constexpr uint32_t axisTensorIdx = 2; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleSplitV(const OMConfigureArgs &config_args) +{ + OMRuntimeContext &runtime_context = config_args.runtime_context; + OMRuntimeStorage &runtime_storage = config_args.runtime_storage; + uint16_t op_index = config_args.kernel_index; + + onert_micro::execute::OMRuntimeKernel runtime_kernel; + + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *size = runtime_kernel.inputs[sizeTensorIdx]; + const circle::Tensor *axis = runtime_kernel.inputs[axisTensorIdx]; + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(axis != nullptr); + assert(size != nullptr); + assert(output != nullptr); + + status = utils::checkCondition(output->type() == input->type()); + if (status != Ok) + return status; + + // Check all outputs have the same type + for (uint32_t i = 1; i < runtime_kernel.outputs_num; ++i) + { + status = utils::checkCondition(output->type() == runtime_kernel.outputs[i]->type()); + if (status != Ok) + return status; + } + + status = utils::checkCondition(axis->type() == circle::TensorType_INT32); + if (status != Ok) + return status; + + status = utils::checkCondition(size->type() == circle::TensorType_INT32); + if (status != Ok) + return status; + + // Check size tensor contains exactly output_nums_tensors values + status = utils::checkCondition(OMRuntimeShape(size).flatSize() == runtime_kernel.outputs_num); + + // Check it is scalar + status = utils::checkCondition(OMRuntimeShape(axis).flatSize() == 1); + if (status != Ok) + return status; + + // Check axis value + runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + auto *axis_data = reinterpret_cast(runtime_kernel.inputs_data[axisTensorIdx]); + status = utils::checkCondition(axis_data != nullptr); + if (status != Ok) + return status; + + int32_t axis_value = axis_data[0]; + + OMRuntimeShape input_shape(input); + if (axis_value < 0) + { + axis_value += input_shape.dimensionsCount() + 1; + } + + status = utils::checkCondition(axis_value <= input_shape.dimensionsCount() and axis_value >= 0); + if (status != Ok) + return status; + + return status; +} diff --git a/onert-micro/onert-micro/src/train/CMakeLists.txt b/onert-micro/onert-micro/src/train/CMakeLists.txt index 6374a9dfc9e..f6c97b36887 100644 --- a/onert-micro/onert-micro/src/train/CMakeLists.txt +++ b/onert-micro/onert-micro/src/train/CMakeLists.txt @@ -14,10 +14,12 @@ set(SOURCES OMBackpropExecutionBuilder.cpp losses_functions/MSE.cpp losses_functions/CrossEntropy.cpp + losses_functions/SparseCrossEntropy.cpp metrics/CrossEntropy.cpp metrics/MAE.cpp metrics/MSE.cpp metrics/Accuracy.cpp + metrics/SparseCrossEntropyAccuracy.cpp train_optimizers/SGD.cpp train_optimizers/Adam.cpp ) diff --git a/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp b/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp new file mode 100644 index 00000000000..4a194c5edbd --- /dev/null +++ b/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "train/losses_functions/SparseCrossEntropy.h" +#include + +using namespace onert_micro; +using namespace onert_micro::train; +using namespace onert_micro::train::losses_functions; + +/* + * dE/dZi = (dE/dy) * (dy / dZi) + * where Z - vector of logits, + * y - probaility of target. + * + * Since dE/dy = -(1/y), + * (true label) if i == y : dE/dZi = py - 1 = y - 1 + * (wrong label) else : dE/dZi = pj + */ +void SparseCrossEntropy::calculateErrorBackpropagation(const uint32_t flat_size, + const float *calculated_data, + const float *target_data, float *output_grad) +{ + uint32_t label = static_cast(target_data[0]); + + for (uint32_t i = 0; i < flat_size; ++i) + { + output_grad[i] = (calculated_data[i] + float(10.0e-32)) - (i == label); + } +} diff --git a/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp b/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp new file mode 100644 index 00000000000..260e66ba2fe --- /dev/null +++ b/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "train/metrics/SparseCrossEntropyAccuracy.h" + +using namespace onert_micro; +using namespace onert_micro::train; +using namespace onert_micro::train::metrics; + +/* + * return 1.0 if predicted class equals to target + * return 0.0 otherwise + */ +float SparseCrossEntropyAccuracy::calculateValue(const uint32_t flat_size, + const float *calculated_data, + const float *target_data) +{ + // Find target class + uint32_t target_class = static_cast(target_data[0]); + + // Find predicted class + float pred_class = 0.f; + float pred_max_val = calculated_data[0]; + for (uint32_t i = 0; i < flat_size; ++i) + { + if (pred_max_val < calculated_data[i]) + { + pred_max_val = calculated_data[i]; + pred_class = static_cast(i); + } + } + + return pred_class == target_class ? 1.0f : 0.0f; +} diff --git a/packaging/nnfw-plugin.pc.in b/packaging/nnfw-plugin.pc.in index e0d9271b725..ef3f42cab2d 100644 --- a/packaging/nnfw-plugin.pc.in +++ b/packaging/nnfw-plugin.pc.in @@ -1,5 +1,5 @@ Name: nnfw-plugin -Description: NNFW API for tizen +Description: onert plugin API Version: @version@ Libs: -L@libdir@ -lonert_core Cflags: -I@includedir@/nnfw -I@includedir@/onert diff --git a/packaging/nnfw.pc.in b/packaging/nnfw.pc.in index d72b81b33b4..4252b83cda4 100644 --- a/packaging/nnfw.pc.in +++ b/packaging/nnfw.pc.in @@ -1,5 +1,5 @@ Name: nnfw -Description: NNFW API for tizen +Description: onert API Version: @version@ Libs: -L@libdir@ -lnnfw-dev Cflags: -I@includedir@/nnfw diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe new file mode 100644 index 00000000000..84203a12d04 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe @@ -0,0 +1,67 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 1 dim: 6 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 1, dim: 1, dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 1 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 1 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: NONE + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule new file mode 100644 index 00000000000..c1f2a827884 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (1, 1, X). + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe new file mode 100644 index 00000000000..d446424c238 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe @@ -0,0 +1,67 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 3 dim: 1 dim: 4 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: RELU + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule new file mode 100644 index 00000000000..acdd2d6a96b --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (X). + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe new file mode 100644 index 00000000000..34e3cde4839 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe @@ -0,0 +1,66 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 16 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 4 dim: 16 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 1 } + filler { + tag: "constant" + arg: "2.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 1 dim: 4 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 1 dim: 4 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: NONE + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule new file mode 100644 index 00000000000..9cc8d5fd0a7 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (1), it's a scalar. + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe new file mode 100644 index 00000000000..2883ebabdf0 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe @@ -0,0 +1,57 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 3 dim: 1 dim: 4 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "scale" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: RELU + } + input: "fc_out" + input: "scale" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule new file mode 100644 index 00000000000..16bb2ff2788 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule @@ -0,0 +1,13 @@ +# This checks if: +# Mul(FC(input, weights, _), other) +# is converted to: +# FC(input, Mul(weights, other), _) +# and then Mul is fused to: +# FC(input, weights', _) +# Here the bias is empty/excluded "_". +# Thus Mul is only fused with weights. + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteSchema/2.16.1/schema.fbs b/res/TensorFlowLiteSchema/2.16.1/schema.fbs new file mode 100644 index 00000000000..382462f938d --- /dev/null +++ b/res/TensorFlowLiteSchema/2.16.1/schema.fbs @@ -0,0 +1,1642 @@ +// Copyright 2017 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Revision History +// Version 0: Initial version. +// Version 1: Add subgraphs to schema. +// Version 2: Rename operators to conform to NN API. +// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers. +// Version 3a: Add new builtin op code field. Has backward compatibility with +// version 3. +// Version 3b: Rename fields in SignatureDef. Has backward compatibility with +// version 3 and 3a. +// Version 3c: Move constant tensor buffers & custom op buffers outside from +// Flatbuffers. Has backward compatibility with version 3, 3a and +// 3b. + +namespace tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// IMPORTANT: All new members of tables, enums and unions must be added at the +// end to ensure backwards compatibility. + +// The type of data stored in a tensor. +enum TensorType : byte { + FLOAT32 = 0, + FLOAT16 = 1, + INT32 = 2, + UINT8 = 3, + INT64 = 4, + STRING = 5, + BOOL = 6, + INT16 = 7, + COMPLEX64 = 8, + INT8 = 9, + FLOAT64 = 10, + COMPLEX128 = 11, + UINT64 = 12, + // Experimental: Resource and variant types are experimental, that are subject + // to change. Do not implement custom kernels using resource & variant types + // now. + RESOURCE = 13, + VARIANT = 14, + UINT32 = 15, + UINT16 = 16, + INT4 = 17, +} + +// Custom quantization parameters for experimenting with new quantization +// techniques. +table CustomQuantization { + custom:[ubyte] (force_align: 16); +} + +// Represents a specific quantization technique's parameters. +union QuantizationDetails { + CustomQuantization, +} + +// Parameters for converting a quantized tensor back to float. +table QuantizationParameters { + // These four parameters are the asymmetric linear quantization parameters. + // Given a quantized value q, the corresponding float value f should be: + // f = scale * (q - zero_point) + // For other quantization types, the QuantizationDetails below is used. + min:[float]; // For importing back into tensorflow. + max:[float]; // For importing back into tensorflow. + scale:[float]; // For dequantizing the tensor's values. + zero_point:[long]; + + // If this is not none, the other quantization parameters (i.e. min, max, + // scale, zero_point fields above) are ignored and the value of the + // QuantizationDetails union should be used. + details:QuantizationDetails; + + // Specifies the dimension of the Tensor's shape that the scales and + // zero_points correspond to. For example, a tensor t, with dims=[4, 3, 2, 1] + // with quantization params: + // scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1 + // will be quantized across the second dimension of t. + // t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1 + // t[:, 1, :, :] will have scale[1]=2.0, zero_point[0]=2 + // t[:, 2, :, :] will have scale[2]=3.0, zero_point[0]=3 + quantized_dimension:int; +} + +// Sparse tensors. +// We use a modification of the TACO format. +// Reference: http://tensor-compiler.org/kjolstad-oopsla17-tensor-compiler.pdf +// +// To encode a conceptual n-dimensional dense tensor with dims (d0, ..., dn-1), +// potentially with a k-dimensional block (0 <= k <= n) with dims +// (dn, ..., dn+k-1), the format needs to specify: +// 1. In what order to traverse these dimensions. For example, to store a 2-D +// matrix in row major order, the traversal order would be (d0, d1), +// whereas to store it in column major order, the traversal order would be +// (d1, d0). If the 2-D matrix has a 2-D inner block, the traversal order +// could be (d0, d1, d2, d3). +// 2. How each block dimension in (dn, ..., dn+k-1) maps to the original +// tensor dimension in (d0, ..., dn-1). +// 3. In the traversal order defined above, the format (dense vs. sparse) and +// index metadata for each dimension. For a dense dimension, this is just +// the size of that dimension. For a sparse dimension, it's the same as +// the compressed index defined in the Compressed Sparse Row (CSR) format. +// (http://scipy-lectures.org/advanced/scipy_sparse/csr_matrix.html) + +// The storage type for a dimension. Currently we support: +// 1. DENSE: each coordinate in this dimension is stored implicitly. +// 2. SPARSE_CSR: only the coordinates with non-zero elements are stored. The +// compression technique is the same what CSR uses. +// More types like a sparse dimension with a different compression technique +// could be added to the list in the future. +enum DimensionType : byte { + DENSE = 0, + SPARSE_CSR = 1, +} + +table Int32Vector { + values:[int]; +} + +table Uint16Vector { + values:[ushort] (force_align: 4); +} + +table Uint8Vector { + values:[ubyte] (force_align: 4); +} + +// Variable-typed buffer to store the index metadata for a sparse dimension. +// The widest type is Int32 instead of UInt32 because tensor's shape is a int32 +// vector. We don't want the per-dimensional index to overflow that range. +union SparseIndexVector { + Int32Vector, + Uint16Vector, + Uint8Vector +} + +table DimensionMetadata { + // Whether a dimension is dense or sparse. + format:DimensionType; + // Index metadata used for a dimension. + // - If format is DimensionType.DENSE then we use the dense_size field to + // store the size of that dimension. Each index in that dimension is + // stored implicitly. + // - If format is DimensionType.SPARSE_CSR then we use array_segments and + // array_indices to encode that dimension. array_segments represents how + // to segment the indices array, each segment corresponds to one element + // in the previous dimension. array_indices represents the index of the + // non-zero elements within this dimension (as those in the CSR matrix + // format, where the first array is row pointers and the second array is + // column indices). + dense_size:int; + array_segments:SparseIndexVector; + array_indices:SparseIndexVector; +} + +// Parameters to encode a sparse TfLite tensor. +table SparsityParameters { + // The traversal order of the dimensions defined in the `shape` field of the + // conceptual dense tensor. For a n-dimensional tensors with dims (d0, d1, + // ..., dn-1), + // - if not block sparse, the traversal_order is just a permutation of (d0, + // ..., dn-1). For example, a 2-D matrix stored in row-major order would + // have traversal_order = (d0, d1). + // - if block sparse with a k-dimensional block (0 <= k <= n), the + // traversal_order has n + k elements. The first n elements are still a + // permutation of (d0, ..., dn-1). The lask k elements are a permutation + // of (dn, ..., dn+k-1), defining how to traverse a block internally. For + // example, a 2-D matrix with 2-D blocks, both stored in row-major order + // would have traversal_order = (d0, d1, d2, d3). + traversal_order:[int]; + // For an n-dimensional tensor with a k-dimensional block (0 <= k <= n), + // stores how a block dimension in (dn, ..., dn+k-1) maps to the original + // tensor dimension in (d0, ..., dn). + // It's stored in the order of (dn, ..., dn+k-1). + // If not block-sparse, this field is NULL. + block_map:[int]; + // In the traversal order defined above, the metadata needed for + // each dimension to locate the non-zero values in the original dense tensor. + // The size of the dim_metadata array = the size of the traversal_order array + // = n + k. + dim_metadata:[DimensionMetadata]; +} + +// The nested tensor type for VARIANT type. +table VariantSubType { + // The tensor shape. + shape:[int]; + type:TensorType; + // If false, the rank or the number of tensor dimensions is unknown. + // If false, "shape" must be []. + has_rank: bool = false; +} + +table Tensor { + // The tensor shape. The meaning of each entry is operator-specific but + // builtin ops use: [batch size, height, width, number of channels] (That's + // Tensorflow's NHWC). + shape:[int]; + type:TensorType; + // An index that refers to the buffers table at the root of the model. Or, + // if there is no data buffer associated (i.e. intermediate results), then + // this is 0 (which refers to an always existent empty buffer). + // + // The data_buffer itself is an opaque container, with the assumption that the + // target device is little-endian. In addition, all builtin operators assume + // the memory is ordered such that if `shape` is [4, 3, 2], then index + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. + buffer:uint; + name:string; // For debugging and importing back into tensorflow. + quantization:QuantizationParameters; // Optional. + + is_variable:bool = false; + + // Parameters to encode a sparse tensor. See the example in + // tensorflow/lite/testdata/sparse_tensor.json. + sparsity:SparsityParameters; // Optional. + + // Encodes `shape` with unknown dimensions. Unknown dimensions are + // represented with -1. + shape_signature:[int]; // Optional. + + // This field is added to distinguish between scalars and tensors of unknown + // ranks (both of which shape is []). + // For scalars (rank = 0), shape = [] and has_rank = true. + // For tensors with known rank (rank > 0) and shape, shape = [...] and + // has_rank = true. + // For tensors with unknown rank and shape, shape = [] and has_rank = false. + has_rank: bool = false; + + // The nested Tensor types for VARIANT type. This is always empty for + // non-VARIANT types. This is optional because the nested type can be omitted. + // Currently only 1 subtype is supported. The field is defined as an array for + // flexibility of supporting multiple subtypes in the future. + variant_tensors:[VariantSubType]; +} + +// A list of builtin operators. Builtin operators are slightly faster than custom +// ones, but not by much. Moreover, while custom operators accept an opaque +// object containing configuration parameters, builtins have a predetermined +// set of acceptable options. +// LINT.IfChange +enum BuiltinOperator : int32 { + ADD = 0, + AVERAGE_POOL_2D = 1, + CONCATENATION = 2, + CONV_2D = 3, + DEPTHWISE_CONV_2D = 4, + DEPTH_TO_SPACE = 5, + DEQUANTIZE = 6, + EMBEDDING_LOOKUP = 7, + FLOOR = 8, + FULLY_CONNECTED = 9, + HASHTABLE_LOOKUP = 10, + L2_NORMALIZATION = 11, + L2_POOL_2D = 12, + LOCAL_RESPONSE_NORMALIZATION = 13, + LOGISTIC = 14, + LSH_PROJECTION = 15, + LSTM = 16, + MAX_POOL_2D = 17, + MUL = 18, + RELU = 19, + // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed + // since different model developers use RELU1 in different ways. Never + // create another op called RELU1. + RELU_N1_TO_1 = 20, + RELU6 = 21, + RESHAPE = 22, + RESIZE_BILINEAR = 23, + RNN = 24, + SOFTMAX = 25, + SPACE_TO_DEPTH = 26, + SVDF = 27, + TANH = 28, + CONCAT_EMBEDDINGS = 29, + SKIP_GRAM = 30, + CALL = 31, + CUSTOM = 32, + EMBEDDING_LOOKUP_SPARSE = 33, + PAD = 34, + UNIDIRECTIONAL_SEQUENCE_RNN = 35, + GATHER = 36, + BATCH_TO_SPACE_ND = 37, + SPACE_TO_BATCH_ND = 38, + TRANSPOSE = 39, + MEAN = 40, + SUB = 41, + DIV = 42, + SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, + BIDIRECTIONAL_SEQUENCE_RNN = 46, + EXP = 47, + TOPK_V2 = 48, + SPLIT = 49, + LOG_SOFTMAX = 50, + // DELEGATE is a special op type for the operations which are delegated to + // other backends. + // WARNING: Experimental interface, subject to change + DELEGATE = 51, + BIDIRECTIONAL_SEQUENCE_LSTM = 52, + CAST = 53, + PRELU = 54, + MAXIMUM = 55, + ARG_MAX = 56, + MINIMUM = 57, + LESS = 58, + NEG = 59, + PADV2 = 60, + GREATER = 61, + GREATER_EQUAL = 62, + LESS_EQUAL = 63, + SELECT = 64, + SLICE = 65, + SIN = 66, + TRANSPOSE_CONV = 67, + SPARSE_TO_DENSE = 68, + TILE = 69, + EXPAND_DIMS = 70, + EQUAL = 71, + NOT_EQUAL = 72, + LOG = 73, + SUM = 74, + SQRT = 75, + RSQRT = 76, + SHAPE = 77, + POW = 78, + ARG_MIN = 79, + FAKE_QUANT = 80, + REDUCE_PROD = 81, + REDUCE_MAX = 82, + PACK = 83, + LOGICAL_OR = 84, + ONE_HOT = 85, + LOGICAL_AND = 86, + LOGICAL_NOT = 87, + UNPACK = 88, + REDUCE_MIN = 89, + FLOOR_DIV = 90, + REDUCE_ANY = 91, + SQUARE = 92, + ZEROS_LIKE = 93, + FILL = 94, + FLOOR_MOD = 95, + RANGE = 96, + RESIZE_NEAREST_NEIGHBOR = 97, + LEAKY_RELU = 98, + SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, + ABS = 101, + SPLIT_V = 102, + UNIQUE = 103, + CEIL = 104, + REVERSE_V2 = 105, + ADD_N = 106, + GATHER_ND = 107, + COS = 108, + WHERE = 109, + RANK = 110, + ELU = 111, + REVERSE_SEQUENCE = 112, + MATRIX_DIAG = 113, + QUANTIZE = 114, + MATRIX_SET_DIAG = 115, + ROUND = 116, + HARD_SWISH = 117, + IF = 118, + WHILE = 119, + NON_MAX_SUPPRESSION_V4 = 120, + NON_MAX_SUPPRESSION_V5 = 121, + SCATTER_ND = 122, + SELECT_V2 = 123, + DENSIFY = 124, + SEGMENT_SUM = 125, + BATCH_MATMUL = 126, + PLACEHOLDER_FOR_GREATER_OP_CODES = 127, + CUMSUM = 128, + CALL_ONCE = 129, + BROADCAST_TO = 130, + RFFT2D = 131, + CONV_3D = 132, + IMAG=133, + REAL=134, + COMPLEX_ABS=135, + HASHTABLE = 136, + HASHTABLE_FIND = 137, + HASHTABLE_IMPORT = 138, + HASHTABLE_SIZE = 139, + REDUCE_ALL = 140, + CONV_3D_TRANSPOSE = 141, + VAR_HANDLE = 142, + READ_VARIABLE = 143, + ASSIGN_VARIABLE = 144, + BROADCAST_ARGS = 145, + RANDOM_STANDARD_NORMAL = 146, + BUCKETIZE = 147, + RANDOM_UNIFORM = 148, + MULTINOMIAL = 149, + GELU = 150, + DYNAMIC_UPDATE_SLICE = 151, + RELU_0_TO_1 = 152, + UNSORTED_SEGMENT_PROD = 153, + UNSORTED_SEGMENT_MAX = 154, + UNSORTED_SEGMENT_SUM = 155, + ATAN2 = 156, + UNSORTED_SEGMENT_MIN = 157, + SIGN = 158, + BITCAST = 159, + BITWISE_XOR = 160, + RIGHT_SHIFT = 161, + // All Operators start with STABLEHLO_ prefixes are subject to change + // Many of the ops below can not be executed by TFlite runtime + STABLEHLO_LOGISTIC = 162, // WARNING: Do not have runtime support + STABLEHLO_ADD = 163, + STABLEHLO_DIVIDE = 164, // WARNING: No runtime support yet + STABLEHLO_MULTIPLY = 165, + STABLEHLO_MAXIMUM = 166, + STABLEHLO_RESHAPE = 167, // WARNING: No runtime support yet + STABLEHLO_CLAMP = 168, // WARNING: No runtime support + STABLEHLO_CONCATENATE = 169, // WARNING: No runtime support + STABLEHLO_BROADCAST_IN_DIM = 170, // WARNING: No runtime support + STABLEHLO_CONVOLUTION = 171, // WARNING: No runtime support + STABLEHLO_SLICE = 172, // WARNING: No runtime support + STABLEHLO_CUSTOM_CALL = 173, // WARNING: No runtime support + STABLEHLO_REDUCE = 174, // WARNING: No runtime support + STABLEHLO_ABS = 175, // WARNING: No runtime support + STABLEHLO_AND = 176, // WARNING: No runtime support + STABLEHLO_COSINE = 177, // WARNING: No runtime support + STABLEHLO_EXPONENTIAL = 178, // WARNING: No runtime support + STABLEHLO_FLOOR = 179, // WARNING: No runtime support + STABLEHLO_LOG = 180, // WARNING: No runtime support + STABLEHLO_MINIMUM = 181, + STABLEHLO_NEGATE = 182, // WARNING: No runtime support + STABLEHLO_OR = 183, // WARNING: No runtime support + STABLEHLO_POWER = 184, // WARNING: No runtime support + STABLEHLO_REMAINDER = 185, // WARNING: No runtime support + STABLEHLO_RSQRT = 186, // WARNING: No runtime support + STABLEHLO_SELECT = 187, // WARNING: No runtime support + STABLEHLO_SUBTRACT = 188, // WARNING: No runtime support + STABLEHLO_TANH = 189, // WARNING: No runtime support + STABLEHLO_SCATTER = 190, + STABLEHLO_COMPARE = 191, // WARNING: No runtime support + STABLEHLO_CONVERT = 192, // WARNING: No runtime support + STABLEHLO_DYNAMIC_SLICE = 193, // WARNING: No runtime support + STABLEHLO_DYNAMIC_UPDATE_SLICE = 194, // WARNING: No runtime support + STABLEHLO_PAD = 195, + STABLEHLO_IOTA = 196, // WARNING: No runtime support + STABLEHLO_DOT_GENERAL = 197, // WARNING: No runtime support + STABLEHLO_REDUCE_WINDOW = 198, + STABLEHLO_SORT = 199, // WARNING: No runtime support + STABLEHLO_WHILE = 200, // WARNING: No runtime support + STABLEHLO_GATHER = 201, + STABLEHLO_TRANSPOSE = 202, // WARNING: No runtime support + DILATE = 203, + STABLEHLO_RNG_BIT_GENERATOR = 204, + REDUCE_WINDOW = 205 (deprecated), +} +// LINT.ThenChange(nnapi_linter/linter.proto) + +// Options for the builtin operators. +union BuiltinOptions { + Conv2DOptions, + DepthwiseConv2DOptions, + ConcatEmbeddingsOptions, + LSHProjectionOptions, + Pool2DOptions, + SVDFOptions, + RNNOptions, + FullyConnectedOptions, + SoftmaxOptions, + ConcatenationOptions, + AddOptions, + L2NormOptions, + LocalResponseNormalizationOptions, + LSTMOptions, + ResizeBilinearOptions, + CallOptions, + ReshapeOptions, + SkipGramOptions, + SpaceToDepthOptions, + EmbeddingLookupSparseOptions, + MulOptions, + PadOptions, + GatherOptions, + BatchToSpaceNDOptions, + SpaceToBatchNDOptions, + TransposeOptions, + ReducerOptions, + SubOptions, + DivOptions, + SqueezeOptions, + SequenceRNNOptions, + StridedSliceOptions, + ExpOptions, + TopKV2Options, + SplitOptions, + LogSoftmaxOptions, + CastOptions, + DequantizeOptions, + MaximumMinimumOptions, + ArgMaxOptions, + LessOptions, + NegOptions, + PadV2Options, + GreaterOptions, + GreaterEqualOptions, + LessEqualOptions, + SelectOptions, + SliceOptions, + TransposeConvOptions, + SparseToDenseOptions, + TileOptions, + ExpandDimsOptions, + EqualOptions, + NotEqualOptions, + ShapeOptions, + PowOptions, + ArgMinOptions, + FakeQuantOptions, + PackOptions, + LogicalOrOptions, + OneHotOptions, + LogicalAndOptions, + LogicalNotOptions, + UnpackOptions, + FloorDivOptions, + SquareOptions, + ZerosLikeOptions, + FillOptions, + BidirectionalSequenceLSTMOptions, + BidirectionalSequenceRNNOptions, + UnidirectionalSequenceLSTMOptions, + FloorModOptions, + RangeOptions, + ResizeNearestNeighborOptions, + LeakyReluOptions, + SquaredDifferenceOptions, + MirrorPadOptions, + AbsOptions, + SplitVOptions, + UniqueOptions, + ReverseV2Options, + AddNOptions, + GatherNdOptions, + CosOptions, + WhereOptions, + RankOptions, + ReverseSequenceOptions, + MatrixDiagOptions, + QuantizeOptions, + MatrixSetDiagOptions, + HardSwishOptions, + IfOptions, + WhileOptions, + DepthToSpaceOptions, + NonMaxSuppressionV4Options, + NonMaxSuppressionV5Options, + ScatterNdOptions, + SelectV2Options, + DensifyOptions, + SegmentSumOptions, + BatchMatMulOptions, + CumsumOptions, + CallOnceOptions, + BroadcastToOptions, + Rfft2dOptions, + Conv3DOptions, + HashtableOptions, + HashtableFindOptions, + HashtableImportOptions, + HashtableSizeOptions, + VarHandleOptions, + ReadVariableOptions, + AssignVariableOptions, + RandomOptions, + BucketizeOptions, + GeluOptions, + DynamicUpdateSliceOptions, + UnsortedSegmentProdOptions, + UnsortedSegmentMaxOptions, + UnsortedSegmentMinOptions, + UnsortedSegmentSumOptions, + ATan2Options, + SignOptions, + BitcastOptions, + BitwiseXorOptions, + RightShiftOptions, + // DO NOT add new options this union, will cause failure in Java api + // generation otherwise + // Add new builtin options into builtin options 2 instead +} + +union BuiltinOptions2{ + StablehloConcatenateOptions, + StablehloBroadcastInDimOptions, + StablehloSliceOptions, + StablehloConvolutionOptions, + StablehloCustomCallOptions, + StablehloReduceOptions, + StablehloScatterOptions, + StablehloCompareOptions, + StablehloDynamicSliceOptions, + StablehloPadOptions, + StablehloIotaOptions, + StablehloDotGeneralOptions, + StablehloReduceWindowOptions, + StablehloSortOptions, + StablehloWhileOptions, + StablehloGatherOptions, + StablehloTransposeOptions, + DilateOptions, + StablehloRngBitGeneratorOptions, + ReduceWindowOptions (deprecated), +} + +table StablehloGatherOptions{ + offset_dims : [long]; + collapsed_slice_dims : [long]; + start_index_map : [long]; + index_vector_dim : long; + slice_sizes : [long]; + indices_are_sorted : bool; +} + +table StablehloTransposeOptions{ + permutation : [long]; +} + +enum StablehloPrecisionConfig : uint { + DEFAULT, + HIGH, + HIGHEST, +} + +table StablehloDotGeneralOptions{ + lhs_batching_dimensions : [long]; + rhs_batching_dimensions : [long]; + lhs_contracting_dimensions : [long]; + rhs_contracting_dimensions : [long]; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloReduceWindowOptions{ + window_dimensions : [long]; + window_strides : [long]; + base_dilations : [long]; + window_dilations : [long]; + padding : [long]; + body_subgraph_index : int; +} + +table StablehloWhileOptions{ + cond_subgraph_index : int; + body_subgraph_index : int; +} + +table StablehloSortOptions{ + dimension : long; + is_stable : bool; + comparator_subgraph_index : int; +} + +table StablehloConcatenateOptions { + dimension : long; +} + +table StablehloBroadcastInDimOptions{ + broadcast_dimensions : [long]; +} + +enum StablehloComparisonDirection : uint { + STABLEHLO_COMPARISON_DIRECTION_EQ, + STABLEHLO_COMPARISON_DIRECTION_NE, + STABLEHLO_COMPARISON_DIRECTION_GE, + STABLEHLO_COMPARISON_DIRECTION_GT, + STABLEHLO_COMPARISON_DIRECTION_LE, + STABLEHLO_COMPARISON_DIRECTION_LT, + +} + +enum StablehloComparisonType : uint { + STABLEHLO_COMPARISON_TYPE_NOTYPE, + STABLEHLO_COMPARISON_TYPE_FLOAT, + STABLEHLO_COMPARISON_TYPE_FLOAT_TOTAL_ORDER, + STABLEHLO_COMPARISON_TYPE_SIGNED, + STABLEHLO_COMPARISON_TYPE_UNSIGNED, +} + +table StablehloCompareOptions{ + comparison_direction : StablehloComparisonDirection; + compare_type : StablehloComparisonType; +} + +table StablehloDynamicSliceOptions{ + slice_sizes : [long]; +} + +table StablehloPadOptions{ + edge_padding_low : [long]; + edge_padding_high : [long]; + interior_padding : [long]; +} + +table StablehloIotaOptions{ + iota_dimension : long; +} + +table StablehloCustomCallOptions { + call_target_name : string; + has_side_effect : bool; + backend_config: string; + api_version : int; // will be decprecated + called_computations: [int]; // should point to subgraphs of the computations + custom_attributes : [ubyte]; +} + +table StablehloReduceOptions { + dimensions : [long]; + body_subgraph_index : int; +} + +table StablehloSliceOptions{ + start_indices : [long]; + limit_indices : [long]; + strides : [long]; +} + +table StablehloConvolutionOptions{ + window_strides : [long]; + padding : [long]; + lhs_dilation : [long]; + rhs_dilation : [long]; + window_reversal : [bool]; + input_batch_dimension : long; + input_feature_dimension : long; + input_spatial_dimensions : [long]; + kernel_input_feature_dimension : long; + kernel_output_feature_dimension : long; + kernel_spatial_dimensions : [long]; + output_batch_dimension : long; + output_feature_dimension : long; + output_spatial_dimensions : [long]; + feature_group_count : long; + batch_group_count : long; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloScatterOptions { + indices_are_sorted: bool; + update_window_dims: [long]; + inserted_window_dims: [long]; + scatter_dims_to_operand_dims: [long]; + index_vector_dim: long; + unique_indices: bool; + update_computation_subgraph_index: int; +} + +enum RngAlgorithm : byte { + // An algorithm auto-selected by the system according to device type. + DEFAULT = 0, + // The Philox algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + PHILOX = 1, + // The ThreeFry algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + THREEFRY = 2, +} + +table StablehloRngBitGeneratorOptions { + algorithm:RngAlgorithm; +} + +// LINT.IfChange +enum Padding : byte { SAME, VALID } +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// LINT.IfChange +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; + // Parameters for Conv2D version 8 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +// Options for both Conv3D and Conv3DTranspose. +table Conv3DOptions { + padding:Padding; + stride_d:int; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_d_factor:int = 1; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table Pool2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + filter_width:int; + filter_height:int; + fused_activation_function:ActivationFunctionType; +} + +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + // `depth_multiplier` is redundant. It's used by CPU kernels in + // TensorFlow 2.0 or below, but ignored in versions above. + // See comments in lite/c/builtin_op_data.h for more details. + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table ConcatEmbeddingsOptions { + num_channels:int; + num_columns_per_channel:[int]; + embedding_dim_per_channel:[int]; // This could be inferred from parameters. +} + +enum LSHProjectionType: byte { + UNKNOWN = 0, + SPARSE = 1, + DENSE = 2, +} + +table LSHProjectionOptions { + type: LSHProjectionType; +} + +table SVDFOptions { + rank:int; + fused_activation_function:ActivationFunctionType; + // For weights-only quantization, use asymmetric quantization for non + // constant inputs at evaluation time. + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + merge_outputs: bool; + asymmetric_quantize_inputs:bool; +} + +// LINT.IfChange +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// An implementation of TensorFlow fully_connected (a.k.a Dense) layer. +table FullyConnectedOptions { + // Parameters for FullyConnected version 1 or above. + fused_activation_function:ActivationFunctionType; + + // Parameters for FullyConnected version 2 or above. + weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT; + + // Parameters for FullyConnected version 5 or above. + // If set to true, then the number of dimension is preserved. Furthermore, + // all but the last dimension of the input and output shapes will be equal. + keep_num_dims: bool; + + // Parameters for FullyConnected version 7 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; + + // Parameters for FullyConnected version 11 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 3. + pot_scale_int16:bool = true; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + // This field is currently ignored in the L2 Norm Op. + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +// LINT.IfChange +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell +table LSTMOptions { + // Parameters for LSTM version 1 or above. + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // Parameters for LSTM version 2 or above. + // Basic kernel is only supported in version 2 or above. + kernel_type: LSTMKernelType = FULL; + + // Parameters for LSTM version 4 or above. + asymmetric_quantize_inputs: bool; +} + +// An implementation of TensorFlow dynamic_rnn with LSTMCell. +table UnidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true then first dimension is sequence, otherwise batch. + time_major:bool; + + // Parameter for Unidirectional Sequence LSTM version 3. + asymmetric_quantize_inputs:bool; + + // Parameter for unidirectional sequence RNN version 4. + diagonal_recurrent_tensors:bool; +} + +table BidirectionalSequenceLSTMOptions { + // Parameters supported by version 1: + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true, store the outputs of both directions into the first output. + merge_outputs: bool; + + // Parameters supported by version 2: + // If true then first dimension is sequence, otherwise batch. + // Version 1 implementations assumed time_major to be true, so this default + // value should never change. + time_major: bool = true; + + // Parameters for version 3 or above. + asymmetric_quantize_inputs:bool; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; + half_pixel_centers: bool; +} + +table ResizeNearestNeighborOptions { + align_corners: bool; + half_pixel_centers: bool; +} + +// A call operation options +table CallOptions { + // The subgraph index that needs to be called. + subgraph:uint; +} + +table PadOptions { +} + +table PadV2Options { +} + +table ReshapeOptions { + new_shape:[int]; +} + +table SpaceToBatchNDOptions { +} + +table BatchToSpaceNDOptions { +} + +table SkipGramOptions { + ngram_size: int; + max_skip_size: int; + include_all_ngrams: bool; +} + +table SpaceToDepthOptions { + block_size: int; +} + +table DepthToSpaceOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 5 + pot_scale_int16:bool = true; +} + +table DivOptions { + fused_activation_function:ActivationFunctionType; +} + +table TopKV2Options { +} + +enum CombinerType : byte { + SUM = 0, + MEAN = 1, + SQRTN = 2, +} + +table EmbeddingLookupSparseOptions { + combiner:CombinerType; +} + +table GatherOptions { + axis: int; + // Parameters for Gather version 5 or above. + batch_dims: int = 0; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table CosOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table SplitVOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; + // If true, then the end tensor is an offset of the begin tensor. + offset: bool; +} + +table LogSoftmaxOptions { +} + +table CastOptions { + in_data_type: TensorType; + out_data_type: TensorType; +} + +table DequantizeOptions { +} + +table MaximumMinimumOptions { +} + +table TileOptions { +} + +table ArgMaxOptions { + output_type : TensorType; +} + +table ArgMinOptions { + output_type : TensorType; +} + +table GreaterOptions { +} + +table GreaterEqualOptions { +} + +table LessOptions { +} + +table LessEqualOptions { +} + +table NegOptions { +} + +table SelectOptions { +} + +table SliceOptions { +} + +table TransposeConvOptions { + // Parameters supported by version 1, 2, 3: + padding:Padding; + stride_w:int; + stride_h:int; + + // Parameters supported by version 4: + fused_activation_function:ActivationFunctionType = NONE; + + // Parameters for TransposeConv version 5 or above. + // If set, use this for bias and accumulator. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +table ExpandDimsOptions { +} + +table SparseToDenseOptions { + validate_indices:bool; +} + +table EqualOptions { +} + +table NotEqualOptions { +} + +table ShapeOptions { + // Optional output type of the operation (int32 or int64). Defaults to int32. + out_type : TensorType; +} + +table RankOptions { +} + +table PowOptions { +} + +table FakeQuantOptions { + // Parameters supported by version 1: + min:float; + max:float; + num_bits:int; + + // Parameters supported by version 2: + narrow_range:bool; +} + +table PackOptions { + values_count:int; + axis:int; +} + +table LogicalOrOptions { +} + +table OneHotOptions { + axis:int; +} + +table AbsOptions { +} + + +table HardSwishOptions { +} + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +table FloorModOptions { +} + +table RangeOptions { +} + +table LeakyReluOptions { + alpha:float; +} + +table SquaredDifferenceOptions { +} + +// LINT.IfChange +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table MirrorPadOptions { + mode:MirrorPadMode; +} + +table UniqueOptions { + idx_out_type:TensorType = INT32; +} + +table ReverseV2Options { +} + +table AddNOptions { +} + +table GatherNdOptions { +} + +table WhereOptions { +} + +table ReverseSequenceOptions { + seq_dim:int; + batch_dim:int = 0; +} + +table MatrixDiagOptions { +} + +table QuantizeOptions { +} + +table MatrixSetDiagOptions { +} + +table IfOptions { + then_subgraph_index:int; + else_subgraph_index:int; +} + +table CallOnceOptions { + init_subgraph_index:int; +} + +table WhileOptions { + cond_subgraph_index:int; + body_subgraph_index:int; +} + +table NonMaxSuppressionV4Options { +} + +table NonMaxSuppressionV5Options { +} + +table ScatterNdOptions { +} + +table SelectV2Options { +} + +table DensifyOptions { +} + +table SegmentSumOptions { +} + +table BatchMatMulOptions { + adj_x:bool; + adj_y:bool; + // Parameters for BatchMatMul version 4 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; +} + +table CumsumOptions { + exclusive:bool; + reverse:bool; +} + +table BroadcastToOptions { +} + +table Rfft2dOptions { +} + +table HashtableOptions { + // The identity of hash tables. This identity will be used across different + // subgraphs in the same interpreter instance. + table_id:int; + key_dtype:TensorType; + value_dtype:TensorType; +} + +table HashtableFindOptions { +} + +table HashtableImportOptions { +} + +table HashtableSizeOptions { +} + +table VarHandleOptions { + container:string; + shared_name:string; +} + +table ReadVariableOptions { +} + +table AssignVariableOptions { +} + +table RandomOptions { + seed: long; + seed2: long; +} + +table BucketizeOptions { + boundaries: [float]; // The bucket boundaries. +} + +table GeluOptions { + approximate: bool; +} + +table DynamicUpdateSliceOptions { +} + +table UnsortedSegmentProdOptions { +} + +table UnsortedSegmentMaxOptions { +} + +table UnsortedSegmentSumOptions { +} + +table ATan2Options { +} + +table UnsortedSegmentMinOptions{ +} + +table SignOptions { +} + +table BitcastOptions { +} + +table BitwiseXorOptions { +} + +table RightShiftOptions { +} + +table DilateOptions { +} + +enum ReduceWindowFunction : int { + UNSUPPORTED, + ADD, + MUL, + MINIMUM, + MAXIMUM, + ALL, + ANY, +} + +table ReduceWindowOptions (deprecated) { + reduce_function: ReduceWindowFunction; +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + // This field is for backward compatibility. This field will be used when + // the value of the extended builtin_code field has less than + // BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + deprecated_builtin_code:byte; + custom_code:string; + + // The version of the operator. The version need to be bumped whenever new + // parameters are introduced into an op. + version:int = 1; + + // This field is introduced for resolving op builtin code shortage problem + // (the original BuiltinOperator enum field was represented as a byte). + // This field will be used when the value of the extended builtin_code field + // has greater than BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + builtin_code:BuiltinOperator; +} + +enum CustomOptionsFormat : byte { + FLEXBUFFERS = 0, +} + +// An operator takes tensors as inputs and outputs. The type of operation being +// performed is determined by an index into the list of valid OperatorCodes, +// while the specifics of each operations is configured using builtin_options +// or custom_options. +table Operator { + // Index into the operator_codes array. Using an integer here avoids + // complicate map lookups. + opcode_index:uint; + + // Optional input are indicated by -1. + inputs:[int]; + outputs:[int]; + + builtin_options:BuiltinOptions; + custom_options:[ubyte]; + custom_options_format:CustomOptionsFormat; + + // A list of booleans indicating the input tensors which are being mutated by + // this operator.(e.g. used by RNN and LSTM). + // For example, if the "inputs" array refers to 5 tensors and the second and + // fifth are mutable variables, then this list will contain + // [false, true, false, false, true]. + // + // If the list is empty, no variable is mutated in this operator. + // The list either has the same length as `inputs`, or is empty. + mutating_variable_inputs:[bool]; + + // A list of indices to the subgraph's "tensors" that are internal to an Op. + // Internal tensors are those that do not flow in or out of the operation, + // but instead are part of internal computation. As such, the operation's + // implementation may manage its memory more efficiently. They are needed + // however (i.e. not just an implementation detail) since they are part of the + // computation, which may require relevant metadata such as quantization + // parameters. + intermediates:[int]; + + // When an op is using custom_options in a model that is larger than 2GB, then + // we instead use the following attributes to find the buffer location which + // is stored outside of flatbuffers, the offset is calculated relative to the + // beginning of the file and is only valid if > 1 + large_custom_options_offset: ulong; + large_custom_options_size: ulong; + + // Flatbuffers union struct has a 128 elements limit in JAVA, so a second + // union is added, in the case of where BuitlinOptions2 runs out, a third + // one can be added + builtin_options_2 : BuiltinOptions2; +} + +// The root type, defining a subgraph, which typically represents an entire +// model. +table SubGraph { + // A list of all tensors used in this subgraph. + tensors:[Tensor]; + + // Indices of the tensors that are inputs into this subgraph. Note this is + // the list of non-static tensors that feed into the subgraph for inference. + inputs:[int]; + + // Indices of the tensors that are outputs out of this subgraph. Note this is + // the list of output tensors that are considered the product of the + // subgraph's inference. + outputs:[int]; + + // All operators, in execution order. + operators:[Operator]; + + // Name of this subgraph (used for debugging). + name:string; +} + +// Table of raw data buffers (used for constant tensors). Referenced by tensors +// by index. The generous alignment accommodates mmap-friendly data structures. +table Buffer { + data:[ubyte] (force_align: 16); + + // In a model that is larger than 2GB, then buffers instead uses the following + // attributes to find stored data, which is outside of flatbuffers + // the offset is calculated relative to the beginning of the file and is only + // valid if > 1. + offset: ulong; + size: ulong; +} + +table Metadata { + // A human readable string to uniquely identify a Metadata. + name:string; + // An index to the buffers table. + buffer:uint; +} + +// Map from an alias name of tensor to tensor index in the graph. +// This is used in Signature def. +table TensorMap { + // Represents the alias to use for this tensor. + name:string; + + // The actual tensor index in the primary graph, that 'name' corresponds to. + tensor_index:uint; +} + +// This corresponds to SignatureDef in Tensorflow SavedModel. +// The SignatureDef will be part of the SavedModel provided for conversion. +table SignatureDef { + // Named inputs for this signature. + inputs:[TensorMap]; + + // Named outputs for this signature. + outputs:[TensorMap]; + + // Key value which was in the Tensorflow SavedModel SignatureDef map. + signature_key:string; + + // Model tag, deprecated. + deprecated_tag:string (deprecated); + + // Index of subgraphs that corresponds to the exported method. + subgraph_index:uint; +} + +table Model { + // Version of the schema. + version:uint; + + // A list of all operator codes used in this model. This is + // kept in order because operators carry an index into this + // vector. + operator_codes:[OperatorCode]; + + // All the subgraphs of the model. The 0th is assumed to be the main + // model. + subgraphs:[SubGraph]; + + // A description of the model. + description:string; + + // Buffers of the model. + // Note the 0th entry of this array must be an empty buffer (sentinel). + // This is a convention so that tensors without a buffer can provide 0 as + // their buffer. + buffers:[Buffer]; + + // Metadata about the model. Indirects into the existings buffers list. + // Deprecated, prefer to use metadata field. + metadata_buffer:[int]; + + // Metadata about the model. + metadata:[Metadata]; + + // Optional SignatureDefs for the model. + signature_defs:[SignatureDef]; +} + +root_type Model; diff --git a/runtime/onert/api/python/package/__init__.py b/runtime/onert/api/python/package/__init__.py index cd1eaccc9d3..05e235a3112 100644 --- a/runtime/onert/api/python/package/__init__.py +++ b/runtime/onert/api/python/package/__init__.py @@ -1,2 +1,2 @@ -__all__ = ['libnnfw_api_pybind'] -from . import libnnfw_api_pybind +__all__ = ['infer'] +from . import infer diff --git a/runtime/onert/api/python/package/libnnfw_api_pybind.py b/runtime/onert/api/python/package/infer.py similarity index 95% rename from runtime/onert/api/python/package/libnnfw_api_pybind.py rename to runtime/onert/api/python/package/infer.py index f9d51e91dc8..146c4b03efc 100644 --- a/runtime/onert/api/python/package/libnnfw_api_pybind.py +++ b/runtime/onert/api/python/package/infer.py @@ -2,7 +2,7 @@ import os import shutil -from .onert import libnnfw_api_pybind +from .native import libnnfw_api_pybind def num_elems(tensor_info): @@ -13,7 +13,7 @@ def num_elems(tensor_info): return n -class nnfw_session(libnnfw_api_pybind.nnfw_session): +class session(libnnfw_api_pybind.nnfw_session): """Class inherited nnfw_session for easily processing input/output""" def __init__(self, nnpackage_path, backends="cpu"): diff --git a/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h b/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h index 138ce6dc0d3..79031d656a5 100644 --- a/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h +++ b/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h @@ -120,7 +120,6 @@ class BackendContext : public onert::backend::BackendContext { // These tensors do not exist in any operation (No use and def) const auto &info = obj.info(); - assert(_data.operand_layouts.at(ind) == ir::Layout::NHWC); registerTensorInfo(ind, info); } }); diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc index 9e6de17f2de..9ebaa9b14f7 100644 --- a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc +++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc @@ -28,6 +28,43 @@ namespace cpu namespace ops { +void DepthwiseConvolutionLayer::prepareF32() +{ + if (_dilationWidth != 1 || _dilationHeight != 1 || _strideWidth != _strideHeight) + return; + + // DepthwiseConvOp cpu kernel needs additional memory to perform with multi- + // threads. So, we allocate it here and pass it to the kernel. + const int64_t k_packet_size = nnfw::cker::eigen_support::kPacketSize(); + + const auto out_shape = getShape(_output); + const auto filter_shape = getShape(_kernel); + const int batch = out_shape.Dims(0); + const int out_depth = out_shape.Dims(3); + const int filter_rows = filter_shape.Dims(1); + const int filter_cols = filter_shape.Dims(2); + + const int filter_spatial_size = filter_rows * filter_cols; + const int padded_filter_inner_dim_size = + ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; + + _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; + + // prepare padded_filter buffer for cker + auto padded_filter_info = ir::OperandInfo(_kernel->get_info()); + padded_filter_info.shape({batch, filter_spatial_size, padded_filter_inner_dim_size}); + _padded_filter = std::make_unique(padded_filter_info, nullptr); + _padded_filter->setBuffer(std::make_shared(_padded_filter->total_size())); + + // prepare out_bprop and in_bprop buffer for cker + const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; + + auto filter_buffers_info = ir::OperandInfo(_kernel->get_info()); + filter_buffers_info.shape({thread_count, filter_spatial_size, padded_filter_inner_dim_size}); + _filter_buffers = std::make_unique(filter_buffers_info, nullptr); + _filter_buffers->setBuffer(std::make_shared(_filter_buffers->total_size())); +} + void DepthwiseConvolutionLayer::convFloat32() { float output_activation_min = 0, output_activation_max = 0; @@ -44,10 +81,23 @@ void DepthwiseConvolutionLayer::convFloat32() op_params.float_activation_min = output_activation_min; op_params.float_activation_max = output_activation_max; - nnfw::cker::DepthwiseConv( - op_params, getShape(_input), getBuffer(_input), getShape(_kernel), - getBuffer(_kernel), getShape(_bias), getBuffer(_bias), getShape(_output), - getBuffer(_output), _external_context->ruy_context()); + // Since DepthwiseConvOp does not support dilation and different W/H stride yet, + // it uses the existing kernel in this case. + if (_dilationWidth == 1 && _dilationHeight == 1 && _strideWidth == _strideHeight) + { + nnfw::cker::DepthwiseConvOp(op_params, getShape(_input), getBuffer(_input), + getShape(_kernel), getBuffer(_kernel), getShape(_bias), + getBuffer(_bias), getBuffer(_padded_filter.get()), + _use_padded_filter, getBuffer(_filter_buffers.get()), + getShape(_output), getBuffer(_output)); + } + else + { + nnfw::cker::DepthwiseConv( + op_params, getShape(_input), getBuffer(_input), getShape(_kernel), + getBuffer(_kernel), getShape(_bias), getBuffer(_bias), getShape(_output), + getBuffer(_output), _external_context->ruy_context()); + } } void DepthwiseConvolutionLayer::convQ8uPerTensor() @@ -265,6 +315,10 @@ void DepthwiseConvolutionLayer::configure( prepareQ8iHybridPerChannel(); _prepared = true; } + else if (_input->data_type() == OperandType::FLOAT32) + { + prepareF32(); + } else if (_input->data_type() == OperandType::QUANT_INT8_ASYMM) { if (_kernel->is_constant() && !_input->is_dynamic() && !_output->is_dynamic()) diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h index dca36a62a48..62eabe17849 100644 --- a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h +++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h @@ -20,6 +20,7 @@ #include #include "OperationUtils.h" #include "../ExternalContext.h" +#include "../Tensor.h" #include @@ -57,6 +58,7 @@ class DepthwiseConvolutionLayer : public ::onert::exec::IFunction void run() override; private: + void prepareF32(); void prepareQ8i(); void prepareQ8uPerChannel(); void prepareQ8iHybridPerChannel(); @@ -83,6 +85,10 @@ class DepthwiseConvolutionLayer : public ::onert::exec::IFunction ir::Activation _activation{ir::Activation::NONE}; + bool _use_padded_filter{false}; + std::unique_ptr _padded_filter{nullptr}; + std::unique_ptr _filter_buffers{nullptr}; + private: std::shared_ptr _external_context; diff --git a/runtime/onert/backend/train/Backend.h b/runtime/onert/backend/train/Backend.h index 9ba689d0343..debde889329 100644 --- a/runtime/onert/backend/train/Backend.h +++ b/runtime/onert/backend/train/Backend.h @@ -54,7 +54,7 @@ class Backend : public ::onert::backend::Backend, public backend::train::ITraina const auto &tgraph = *tdata.tgraph; auto optimizer = createOptimizer(tdata.optim_info); auto tr = std::make_shared(); - auto tb = std::make_shared(tr, optimizer.get(), "Bump"); + auto tb = std::make_shared(tr, optimizer.get()); auto tdata_ptr = std::make_unique(std::move(tdata)); auto context = std::make_unique(this, std::move(tdata_ptr), tr, tb, std::move(optimizer)); diff --git a/runtime/onert/backend/train/BackendContext.cc b/runtime/onert/backend/train/BackendContext.cc index f5bf9999671..59fee712247 100644 --- a/runtime/onert/backend/train/BackendContext.cc +++ b/runtime/onert/backend/train/BackendContext.cc @@ -136,22 +136,50 @@ getDisposableBackPropTensorList(const ir::train::TrainableGraph &tgraph, } } // namespace -backend::ITensorRegistry *BackendContext::genTensors() +FunctionMap BackendContext::gen() { planForwardTensors(); + planBackwardTensors(); _tensor_builder->allocate(); + _tensor_builder->allocateBackward(); - return _tensor_registry.get(); -} + auto fn_map = generateFunctionMap(); -backend::train::ITensorRegistry *BackendContext::genTrainingTensors() -{ - planBackwardTensors(); + // Initialize TrainableTensors + trainable_graph()->operands().iterate( + [&](const ir::OperandIndex &ind, const ir::Operand &operand) { + if (external_operands().contains(ind) || !operand.isConstant()) + return; - _tensor_builder->allocateBackward(); + auto tensor = tensor_registry()->getNativeITensor(ind); + assert(tensor != nullptr); + + VERBOSE(FillOperandData) << "Fill data for " << ind << std::endl; + + auto data = operand.shareData(); + assert(data && data->base()); + auto trainable_tensor = dynamic_cast(tensor); - return _tensor_registry.get(); + if (trainable_tensor == nullptr) + throw std::runtime_error{"This tensor is not trainable tensor"}; + + trainable_tensor->fillBuffer(data); + }); + + // NOTE For memory optimization, we want to free some operand data + const_cast(*_tdata->tgraph) + .operands() + .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); }); + + // TODO Enable + // for (auto &&it : ret) + // { + // auto &fn_seq = it.second; + // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); + // } + + return fn_map; } void BackendContext::planForwardTensors() @@ -209,46 +237,6 @@ void BackendContext::planBackwardTensors() tensor_planner.planDisposableBackPropTensors(tensor_builder.get()); } -FunctionMap BackendContext::genKernels() -{ - auto ret = generateFunctionMap(); - - // Initialize TrainableTensors - trainable_graph()->operands().iterate( - [&](const ir::OperandIndex &ind, const ir::Operand &operand) { - if (external_operands().contains(ind) || !operand.isConstant()) - return; - - auto tensor = tensor_registry()->getNativeITensor(ind); - assert(tensor != nullptr); - - VERBOSE(FillOperandData) << "Fill data for " << ind << std::endl; - - auto data = operand.shareData(); - assert(data && data->base()); - auto trainable_tensor = dynamic_cast(tensor); - - if (trainable_tensor == nullptr) - throw std::runtime_error{"This tensor is not trainable tensor"}; - - trainable_tensor->fillBuffer(data); - }); - - // NOTE For memory optimization, we want to free some operand data - const_cast(*_tdata->tgraph) - .operands() - .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); }); - - // TODO Enable - // for (auto &&it : ret) - // { - // auto &fn_seq = it.second; - // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); - // } - - return ret; -} - FunctionMap BackendContext::generateFunctionMap() { train::FunctionMap ret; diff --git a/runtime/onert/backend/train/BackendContext.h b/runtime/onert/backend/train/BackendContext.h index 69d17d352c4..8e343aee403 100644 --- a/runtime/onert/backend/train/BackendContext.h +++ b/runtime/onert/backend/train/BackendContext.h @@ -68,16 +68,13 @@ class BackendContext : public onert::backend::train::TrainableBackendContext BackendContext &operator=(const BackendContext &) = delete; public: - backend::ITensorRegistry *genTensors() override; - backend::train::ITensorRegistry *genTrainingTensors() override; + FunctionMap gen() override; private: void planForwardTensors(); void planBackwardTensors(); public: - FunctionMap genKernels() override; - std::shared_ptr external_context() { return _external_context; } const exec::train::optimizer::Optimizer *optimizer() const { return _optimizer.get(); } diff --git a/runtime/onert/backend/train/ExtraTensorIndex.h b/runtime/onert/backend/train/ExtraTensorIndex.h new file mode 100644 index 00000000000..84fbf6c1c6e --- /dev/null +++ b/runtime/onert/backend/train/ExtraTensorIndex.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ +#define __ONERT_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace train +{ + +class ExtraTensorIndex +{ +public: + ExtraTensorIndex(const ir::OperationIndex &op_index, uint32_t sub_index) + : _op_index{op_index}, _sub_index{sub_index} + { + assert(op_index.valid()); + } + +public: + const ir::OperationIndex &op_index() const { return _op_index; } + uint32_t sub_index() const { return _sub_index; } + + bool operator==(const ExtraTensorIndex &other) const + { + return _op_index == other.op_index() && _sub_index == other.sub_index(); + } + bool operator!=(const ExtraTensorIndex &other) const { return !(*this == other); } + +private: + ir::OperationIndex _op_index; + uint32_t _sub_index; +}; + +inline std::ostream &operator<<(std::ostream &o, const ExtraTensorIndex &i) +{ + o << i.op_index() << "-" << i.sub_index(); + return o; +} + +} // namespace train +} // namespace backend +} // namespace onert + +namespace std +{ + +template <> struct hash +{ + size_t operator()(const onert::backend::train::ExtraTensorIndex &index) const noexcept + { + const auto op_index = index.op_index(); + const auto sub_index = index.sub_index(); + + assert(sizeof(op_index) <= sizeof(uint32_t)); + static_assert(sizeof(size_t) >= sizeof(uint32_t), + "ExtraTensorIndex's hash creation error, size_t size is less than uint32_t"); + + return (static_cast(op_index.value())) << 16 | static_cast(sub_index); + } +}; + +} // namespace std + +#endif // __ONERT_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ diff --git a/runtime/onert/backend/train/MemoryManager.cc b/runtime/onert/backend/train/MemoryManager.cc index 87cd15d55a8..4902e2a7eaa 100644 --- a/runtime/onert/backend/train/MemoryManager.cc +++ b/runtime/onert/backend/train/MemoryManager.cc @@ -29,14 +29,13 @@ namespace backend namespace train { -GradientMemoryManager::GradientMemoryManager(const std::string planner_id, - uint32_t optim_vars_count) - : MemoryManager{planner_id}, _optim_vars_count{optim_vars_count} +TrainableMemoryManager::TrainableMemoryManager(uint32_t optim_vars_count) + : _optim_vars_count{optim_vars_count} { // DO NOTHING } -void GradientMemoryManager::allocate(void) +void TrainableMemoryManager::allocate(void) { _mem_alloc = std::make_shared(_mem_planner->capacity()); assert(_mem_alloc->base()); @@ -45,7 +44,8 @@ void GradientMemoryManager::allocate(void) _var_mem_alloc = std::make_shared(vars_capacity); } -uint8_t *GradientMemoryManager::getOptVarBuffer(const ir::OperandIndex &ind, uint32_t pos_var) const +uint8_t *TrainableMemoryManager::getOptVarBuffer(const ir::OperandIndex &ind, + uint32_t pos_var) const { assert(_mem_planner->memory_plans().find(ind) != _mem_planner->memory_plans().end()); const auto var_offset = pos_var * _mem_planner->capacity(); @@ -58,12 +58,6 @@ DisposableMemoryManager::DisposableMemoryManager() : _mem_planner{createMemoryPl // DO NOTHING } -DisposableMemoryManager::DisposableMemoryManager(const std::string planner_id) - : _mem_planner{createMemoryPlanner(planner_id)} -{ - // DO NOTHING -} - basic::IMemoryPlanner *DisposableMemoryManager::createMemoryPlanner() { auto planner_id = util::getConfigString(util::config::CPU_MEMORY_PLANNER); diff --git a/runtime/onert/backend/train/MemoryManager.h b/runtime/onert/backend/train/MemoryManager.h index 987cf905100..19a60e32deb 100644 --- a/runtime/onert/backend/train/MemoryManager.h +++ b/runtime/onert/backend/train/MemoryManager.h @@ -30,11 +30,11 @@ namespace train using MemoryManager = backend::basic::MemoryManager; -class GradientMemoryManager : public MemoryManager +class TrainableMemoryManager : public MemoryManager { public: - GradientMemoryManager(const std::string planner_id, uint32_t optimizer_vars_count); - virtual ~GradientMemoryManager() = default; + TrainableMemoryManager(uint32_t optimizer_vars_count); + virtual ~TrainableMemoryManager() = default; void allocate(void); uint8_t *getOptVarBuffer(const ir::OperandIndex &ind, uint32_t pos_var) const; @@ -48,7 +48,6 @@ class DisposableMemoryManager { public: DisposableMemoryManager(); - DisposableMemoryManager(const std::string planner_id); void allocate(void); uint8_t *getBuffer(const DisposableTensorIndex &ind) const; diff --git a/runtime/onert/backend/train/TensorBuilder.cc b/runtime/onert/backend/train/TensorBuilder.cc index 80452858057..ee737222be2 100644 --- a/runtime/onert/backend/train/TensorBuilder.cc +++ b/runtime/onert/backend/train/TensorBuilder.cc @@ -26,10 +26,8 @@ namespace train { TensorBuilder::TensorBuilder(const std::shared_ptr &tensor_reg, - const exec::train::optimizer::Optimizer *optimizer, - const std::string planner_id) - : _tensor_reg{tensor_reg}, - _tensor_mgr{new TensorManager(tensor_reg, planner_id, optimizer->getVarCount())}, + const exec::train::optimizer::Optimizer *optimizer) + : _tensor_reg{tensor_reg}, _tensor_mgr{new TensorManager(tensor_reg, optimizer->getVarCount())}, _optimizer{optimizer} { /* empty */ diff --git a/runtime/onert/backend/train/TensorBuilder.h b/runtime/onert/backend/train/TensorBuilder.h index f6ffbbb0e20..1fa46855142 100644 --- a/runtime/onert/backend/train/TensorBuilder.h +++ b/runtime/onert/backend/train/TensorBuilder.h @@ -36,7 +36,7 @@ class TensorBuilder { public: TensorBuilder(const std::shared_ptr &tensor_reg, - const exec::train::optimizer::Optimizer *optimizer, const std::string planner_id); + const exec::train::optimizer::Optimizer *optimizer); /** * @brief Register tensor information to allocate on train backend diff --git a/runtime/onert/backend/train/TensorManager.cc b/runtime/onert/backend/train/TensorManager.cc index cf5373fae74..d8404fcc9ed 100644 --- a/runtime/onert/backend/train/TensorManager.cc +++ b/runtime/onert/backend/train/TensorManager.cc @@ -53,13 +53,12 @@ namespace backend namespace train { -TensorManager::TensorManager(const std::shared_ptr ®, - const std::string planner_id, uint32_t optim_vars_count) - : _nonconst_mgr{new MemoryManager(planner_id)}, _trainable_mgr{new MemoryManager(planner_id)}, - _back_prop_mgr{new MemoryManager(planner_id)}, - _gradient_mgr{new GradientMemoryManager(planner_id, optim_vars_count)}, +TensorManager::TensorManager(const std::shared_ptr ®, uint32_t optim_vars_count) + : _nonconst_mgr{new MemoryManager()}, + _trainable_mgr{new TrainableMemoryManager(optim_vars_count)}, + _back_prop_mgr{new MemoryManager()}, _gradient_mgr{new MemoryManager()}, // TODO Find a suitable planner of disposable tensors to reduce peak memory usage - _disposable_back_prop_mgr{new DisposableMemoryManager(std::string("WIC"))}, _tensors{reg} + _disposable_back_prop_mgr{new DisposableMemoryManager()}, _tensors{reg} { // DO NOTHING } @@ -74,6 +73,19 @@ void TensorManager::allocateTrainableTensors() { allocateMemory(_trainable_mgr.get(), _tensors->trainable_tensors(), std::string{" TRAINABLE TENSOR "}); + + // Set buffers of optimizer variables + // Allocating optimizer variables has been done when calling allocate() of TrainableMemoryManager + for (const auto &[index, trainable_tensor] : _tensors->trainable_tensors()) + { + for (uint32_t var_pos = 0; var_pos < trainable_tensor->optVars().size(); ++var_pos) + { + auto *buffer = _trainable_mgr.get()->getOptVarBuffer(index, var_pos); + trainable_tensor->setOptVarBuffer(buffer, var_pos); + VERBOSE(TensorManager) << std::string{" OPTIM_VAR TENSOR "} << index << " : " + << static_cast(buffer) << std::endl; + } + } } void TensorManager::allocateBackPropTensors() @@ -86,21 +98,6 @@ void TensorManager::allocateGradientTensors() { allocateMemory(_gradient_mgr.get(), _tensors->gradient_tensors(), std::string{" GRADIENT TENSOR "}); - - // Set buffers of optimizer variables - // Allocating optimizer variables has been done when calling allocate() of GradientMemoryManager - for (const auto &pair : _tensors->gradient_tensors()) - { - const auto &index = pair.first; - const auto trainable_tensor = _tensors->trainable_tensors().at(index).get(); - for (uint32_t var_pos = 0; var_pos < trainable_tensor->optVars().size(); ++var_pos) - { - auto *buffer = _gradient_mgr.get()->getOptVarBuffer(index, var_pos); - trainable_tensor->setOptVarBuffer(buffer, var_pos); - VERBOSE(TensorManager) << std::string{" OPTIM_VAR TENSOR "} << index << " : " - << static_cast(buffer) << std::endl; - } - } } void TensorManager::allocateDisposableBackPropTensors() diff --git a/runtime/onert/backend/train/TensorManager.h b/runtime/onert/backend/train/TensorManager.h index f8d29b16e1d..6e0910e182d 100644 --- a/runtime/onert/backend/train/TensorManager.h +++ b/runtime/onert/backend/train/TensorManager.h @@ -41,8 +41,7 @@ class TensorManager static constexpr uint64_t _align = 16; public: - TensorManager(const std::shared_ptr ®, const std::string planner_id, - uint32_t optim_vars_count); + TensorManager(const std::shared_ptr ®, uint32_t optim_vars_count); virtual ~TensorManager() = default; void allocateNonConstTensors(); @@ -65,9 +64,9 @@ class TensorManager private: std::unique_ptr _nonconst_mgr; - std::unique_ptr _trainable_mgr; + std::unique_ptr _trainable_mgr; std::unique_ptr _back_prop_mgr; - std::unique_ptr _gradient_mgr; + std::unique_ptr _gradient_mgr; std::unique_ptr _disposable_back_prop_mgr; const std::shared_ptr _tensors; }; diff --git a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc index 9443d0fe0ea..6a6c8684679 100644 --- a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc +++ b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc @@ -34,7 +34,6 @@ namespace ops DepthwiseConvolutionLayer::DepthwiseConvolutionLayer() : cpu::ops::DepthwiseConvolutionLayer(), _grad_weights{nullptr}, _grad_bias{nullptr}, _back_prop_input{nullptr}, _back_prop_output{nullptr}, _act_back_prop_output{nullptr}, - _use_padded_filter{false}, _padded_filter{nullptr}, _filter_buffers{nullptr}, _filter_dim_buffers{nullptr} { // DO NOTHING @@ -75,34 +74,16 @@ void DepthwiseConvolutionLayer::configureBackward(IPortableTensor *back_prop_inp }(); const auto incoming_shape = getShape(_back_prop_output); - const auto filter_shape = getShape(_kernel); - const int batch = incoming_shape.Dims(0); const int out_depth = incoming_shape.Dims(3); - const int filter_rows = filter_shape.Dims(1); - const int filter_cols = filter_shape.Dims(2); - const int filter_spatial_size = filter_rows * filter_cols; const int padded_filter_inner_dim_size = ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; - _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; - - // prepare padded_filter buffer for cker - auto padded_filter_info = ir::OperandInfo(_kernel->get_info()); - padded_filter_info.shape({batch, filter_spatial_size, padded_filter_inner_dim_size}); - _padded_filter = std::make_unique(padded_filter_info); - _padded_filter->setBuffer(std::make_shared(_padded_filter->total_size())); - // prepare out_bprop and in_bprop buffer for cker // NOTE The Eigen library uses both main thread as well as a thread pool. // Therefore, it needs to add an additional memory buffer for main thread. const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; - auto filter_buffers_info = ir::OperandInfo(_kernel->get_info()); - filter_buffers_info.shape({thread_count, filter_spatial_size, padded_filter_inner_dim_size}); - _filter_buffers = std::make_unique(filter_buffers_info); - _filter_buffers->setBuffer(std::make_shared(_filter_buffers->total_size())); - auto filter_dim_buffers_info = ir::OperandInfo(_back_prop_input->get_info()); filter_dim_buffers_info.shape({thread_count, padded_filter_inner_dim_size}); _filter_dim_buffers = std::make_unique(filter_dim_buffers_info); diff --git a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h index 5cd98e56721..8f286b8040d 100644 --- a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h +++ b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h @@ -56,9 +56,6 @@ class DepthwiseConvolutionLayer : public ::onert::exec::train::ITrainableFunctio // TODO Consider if these tensors should be built in TensorBuilder std::unique_ptr _act_back_prop_output; - bool _use_padded_filter; - std::unique_ptr _padded_filter; - std::unique_ptr _filter_buffers; std::unique_ptr _filter_dim_buffers; }; diff --git a/runtime/onert/core/include/backend/BackendContext.h b/runtime/onert/core/include/backend/BackendContext.h index a00f739cc3a..052809f7d11 100644 --- a/runtime/onert/core/include/backend/BackendContext.h +++ b/runtime/onert/core/include/backend/BackendContext.h @@ -42,8 +42,6 @@ struct ContextData std::vector op_order; /* Operands that are defined by other backends */ util::Set external_operands; - /* Operand layout info */ - ir::OperandIndexMap operand_layouts; /* Custom kernel builder */ std::shared_ptr custom_kernel_builder; /* Is linear executor or not */ @@ -64,7 +62,6 @@ class BackendContext const Backend *backend() const { return _backend; } const ir::Graph *graph() const { return _data.graph.get(); } const util::Set &external_operands() const { return _data.external_operands; } - const ir::OperandIndexMap &operand_layouts() const { return _data.operand_layouts; } const ContextData &data() const { return _data; } virtual ITensorRegistry *genTensors() = 0; diff --git a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h index 590ae0b9919..79a535559e1 100644 --- a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h +++ b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h @@ -61,11 +61,6 @@ template void planTensors(const T_BackendContext &ct { // These tensors do not exist in any (No use and def) const auto &info = obj.info(); - // NOTE Currently we only support NHWC tensors for cpu-common tensors. - // There is no way to get the layout info from the backend context for now. - // When we support NCHW tensors as well, we also need to change tensor info to be - // permuted shape. - assert(ctx.operand_layouts().at(ind) == ir::Layout::NHWC); tensor_builder->registerTensorInfo(ind, info); } }); diff --git a/runtime/onert/core/include/backend/basic/Tensor.h b/runtime/onert/core/include/backend/basic/Tensor.h index 9271faa21a2..92d98f82e13 100644 --- a/runtime/onert/core/include/backend/basic/Tensor.h +++ b/runtime/onert/core/include/backend/basic/Tensor.h @@ -41,8 +41,8 @@ class Tensor : public IPortableTensor public: Tensor(const ir::OperandInfo &info, DynamicMemoryManager *dynamic_mem_mgr) - : IPortableTensor(info), _layout(ir::Layout::NHWC), _buffer(nullptr), _num_references(0), - _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr) + : IPortableTensor(info), _layout(ir::Layout::NHWC), _buffer(nullptr), _size(info.total_size()), + _num_references(0), _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr) { // DO NOTHING } @@ -128,6 +128,7 @@ class Tensor : public IPortableTensor protected: const ir::Layout _layout; uint8_t *_buffer; + size_t _size; int32_t _num_references; DynamicMemoryManager *_dynamic_mem_mgr; diff --git a/runtime/onert/core/include/backend/train/TrainableBackendContext.h b/runtime/onert/core/include/backend/train/TrainableBackendContext.h index b3a9cdd7d52..c2edf0deb79 100644 --- a/runtime/onert/core/include/backend/train/TrainableBackendContext.h +++ b/runtime/onert/core/include/backend/train/TrainableBackendContext.h @@ -76,9 +76,7 @@ class TrainableBackendContext std::shared_ptr tensor_registry() { return _tensor_registry; } - virtual ITensorRegistry *genTrainingTensors() = 0; - virtual backend::ITensorRegistry *genTensors() = 0; - virtual FunctionMap genKernels() = 0; + virtual FunctionMap gen() = 0; private: const ITrainableBackend *_backend{nullptr}; diff --git a/runtime/onert/core/include/compiler/PermuteFactor.h b/runtime/onert/core/include/compiler/PermuteFactor.h deleted file mode 100644 index 67ce957bb08..00000000000 --- a/runtime/onert/core/include/compiler/PermuteFactor.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file PermuteFactor.h - * @brief This file contains PermuteFactor class - * @ingroup COM_AI_RUNTIME - */ - -#ifndef __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ -#define __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ - -#include - -#include "ir/Layout.h" - -namespace onert -{ -namespace backend -{ -class Backend; -} // namespace backend -} // namespace onert - -namespace onert -{ -namespace compiler -{ - -/** - * @brief Class that has factors of permutation - */ -class PermuteFactor -{ -public: - /** - * @brief Construct PermuteFactor object. - * @param backend The backend factor - * @param layout The layout factor - */ - PermuteFactor(const backend::Backend *backend, ir::Layout layout) - : _backend{backend}, _layout{layout} - { - // DO NOTHING - } - /** - * @brief Construct PermuteFactor object by copy semantics. - */ - PermuteFactor(const PermuteFactor &f) : _backend{f._backend}, _layout{f._layout} - { - // DO NOTHING - } - /** - * @brief Construct PermuteFactor object by move semantics. - */ - PermuteFactor(PermuteFactor &&) = default; - -public: - /** - * @brief Get backend - * - * @return Backend factor - */ - const backend::Backend *backend() const { return _backend; } - /** - * @brief Get layout - * - * @return Layout factor - */ - ir::Layout layout() const { return _layout; } - -public: - /** - * @brief operator overloading function for `==` - * - * @return Whether two PermuteFactor are the same - */ - bool operator==(const PermuteFactor &other) const - { - return _backend == other.backend() && _layout == other.layout(); - } - /** - * @brief operator overloading function for `!=` - * - * @return Whether two PermuteFactor are differenct - */ - bool operator!=(const PermuteFactor &other) const { return !(*this == other); } - -private: - const backend::Backend *_backend{nullptr}; - ir::Layout _layout{ir::Layout::UNKNOWN}; -}; - -} // namespace compiler -} // namespace onert - -namespace std -{ - -/** - * @brief Structure that provides hash value of PermuteFactor - */ -template <> struct hash -{ - size_t operator()(const onert::compiler::PermuteFactor &factor) const noexcept - { - hash b_hash{}; - hash l_hash{}; - return b_hash(factor.backend()) ^ (l_hash(factor.layout()) << 1); - } -}; - -} // namespace std - -std::ostream &operator<<(std::ostream &os, const onert::compiler::PermuteFactor &obj); - -#endif // __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ diff --git a/runtime/onert/core/include/ir/operation/Permute.h b/runtime/onert/core/include/ir/operation/Permute.h index 10f09b9a03b..4866e9d1613 100644 --- a/runtime/onert/core/include/ir/operation/Permute.h +++ b/runtime/onert/core/include/ir/operation/Permute.h @@ -34,28 +34,32 @@ namespace ir namespace operation { +/** + * @brief Class to represent Permute operation + * @note Permute operation reorders the dimensions of a tensor. + * + * This operation is virtual operation, which is not used on real model, but used internally. + * It was introduced to support various model layout (NHWC, NCHW, etc) and backend layout. + * But currently, model layout and backend layout are always same as NHWC. + * So this operation is used for below cases. + * 1) Handle model output buffer's special case + * 1-1) Model output is comes from model constant + * 1-2) Model output is comes from model input + * 1-3) Model output shares tensor with other model output(s) + * 2) Handle shared tensor between different backend + * + * Q) Why name is still 'Permute'? + * A) It is handled as copy operation on compile phase, + * but it can be permute operation if output buffer layout is changed by API call + */ class Permute : public Operation { -public: - enum class Type - { - NHWC_TO_NCHW, - NCHW_TO_NHWC, - COPY - }; - public: void accept(OperationVisitor &v) const override; OpCode opcode() const final { return OpCode::Permute; } public: - Permute(const OperandIndex &input, const OperandIndex &output, Type type); - -public: - Type getPermuteType() const { return _type; } - -private: - Type _type; + Permute(const OperandIndex &input, const OperandIndex &output); }; } // namespace operation diff --git a/runtime/onert/core/include/ir/train/Checkpoint.h b/runtime/onert/core/include/ir/train/Checkpoint.h new file mode 100644 index 00000000000..8edc8a0aad5 --- /dev/null +++ b/runtime/onert/core/include/ir/train/Checkpoint.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_TRAIN_CHECKPOINT_H__ +#define __ONERT_IR_TRAIN_CHECKPOINT_H__ + +namespace onert +{ +namespace ir +{ +namespace train +{ +namespace checkpoint +{ + +struct __attribute__((packed)) Header +{ + uint16_t magic; + uint8_t schema; + uint8_t reserved; + uint32_t opt1_offset; + uint32_t opt2_offset; + uint32_t other_offset; + uint32_t length; +}; + +struct __attribute__((packed)) Footer +{ + uint32_t cur_step; + uint32_t cur_epoch; +}; + +constexpr uint16_t MAGIC_NUMBER = 429; +constexpr uint8_t SCHEMA_VERSION = 1; + +} // namespace checkpoint +} // namespace train +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_TRAIN_CHECKPOINT_H__ diff --git a/runtime/onert/core/src/backend/basic/Tensor.cc b/runtime/onert/core/src/backend/basic/Tensor.cc index 7f33d4d7432..b23624683bd 100644 --- a/runtime/onert/core/src/backend/basic/Tensor.cc +++ b/runtime/onert/core/src/backend/basic/Tensor.cc @@ -32,40 +32,23 @@ void Tensor::setShape(const ir::Shape &new_shape) { _info.shape(new_shape); } bool Tensor::applyShape(const ir::Shape &new_shape) { - bool previously_dynamic = is_dynamic(); + if (_buffer != nullptr && new_shape == _info.shape()) + return true; - auto allocTensorMem = [&]() { - auto capacity = total_size(); - assert(_dynamic_mem_mgr); - auto alloc = _dynamic_mem_mgr->allocate(this, capacity); - setBuffer(alloc); - }; - - if (!previously_dynamic || buffer() == nullptr) + // Always set shape - when buffer with same or larger size was already allocated, shape could + // differ + _info.shape(new_shape); + set_dynamic(); + if (_buffer == nullptr || _size < _info.total_size()) { - // Always set shape - when buffer with same size was already allocated, shape could differ - setShape(new_shape); - set_dynamic(); - allocTensorMem(); - } - else - { - auto previous_size = total_size(); - auto new_size = new_shape.num_elements() * ir::sizeOfDataType(data_type()); - if (previous_size != new_size) - { - assert(_dynamic_mem_mgr); + assert(_dynamic_mem_mgr); + if (_allocator) _dynamic_mem_mgr->deallocate(this); - setShape(new_shape); - set_dynamic(); - allocTensorMem(); - } - else - { // when buffer with same size was already allocated, shape could differ - setShape(new_shape); - } + _size = _info.total_size(); + setBuffer(_dynamic_mem_mgr->allocate(this, _size)); } + return true; } diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc index 69483eade12..a0cc0f3c930 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc @@ -28,29 +28,19 @@ namespace builtin namespace train { -backend::ITensorRegistry *BackendContext::genTensors() +backend::train::FunctionMap BackendContext::gen() { - // For now, there is no need to generate tensors for forwarding. + // For now, there is no need to generate tensors for forwarding and backwarding. // builtin train backend handles 3 operators: `Permute`, `IF`, `WHILE`. // `Permute`: Tensor generation is not required. // `IF`, `WHILE`: Not supported yet - return tensor_registry().get(); -} -backend::train::ITensorRegistry *BackendContext::genTrainingTensors() -{ - // For now, there is no need to generate tensors for backwarding. - return tensor_registry().get(); -} - -backend::train::FunctionMap BackendContext::genKernels() -{ - backend::train::FunctionMap ret; + backend::train::FunctionMap fn_map; for (auto &&op_ind : _tdata->op_order) { auto tn_seq = kernel_gen->generate(op_ind); - ret.emplace(op_ind, std::move(tn_seq)); + fn_map.emplace(op_ind, std::move(tn_seq)); } trainable_graph()->operands().iterate( @@ -63,13 +53,13 @@ backend::train::FunctionMap BackendContext::genKernels() }); // TODO Enable prepare() - // for (auto &&it : ret) + // for (auto &&it : fn_map) // { // auto &fn_seq = it.second; // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); // } - return ret; + return fn_map; } } // namespace train diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.h b/runtime/onert/core/src/backend/builtin/train/BackendContext.h index 4782756c31c..4b7c165f454 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.h +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.h @@ -46,11 +46,8 @@ class BackendContext : public backend::train::TrainableBackendContext { } - backend::ITensorRegistry *genTensors() override; - backend::train::ITensorRegistry *genTrainingTensors() override; - public: - backend::train::FunctionMap genKernels() override; + backend::train::FunctionMap gen() override; std::shared_ptr external_context() { return _external_context; } diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc index 3cbe5f670eb..ba307d3ae8c 100644 --- a/runtime/onert/core/src/compiler/ExecutorFactory.cc +++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc @@ -169,9 +169,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, init_context_data(backend); auto &partial_graph = *context_data_map[backend].graph; - auto &operand_layouts = context_data_map[backend].operand_layouts; - assert(operand_layouts.find(operand_ind) == operand_layouts.end()); - operand_layouts[operand_ind] = ir::Layout::NHWC; // Copy the operand and insert it to the partial graph auto new_operand = std::make_unique(operand); @@ -191,7 +188,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, auto &partial_graph = *context_data_map[backend].graph; auto &external_operands = context_data_map[backend].external_operands; - auto &operand_layouts = context_data_map[backend].operand_layouts; { // Add missing operands (externals) @@ -210,8 +206,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, UNUSED_RELEASE(new_operand_ind); assert(new_operand_ind == operand_ind); - assert(operand_layouts.find(operand_ind) == operand_layouts.end()); - operand_layouts[operand_ind] = ir::Layout::NHWC; external_operands.add(operand_ind); } @@ -274,6 +268,21 @@ std::deque> orderBackendContext( return ordered_contexts; } +void generateCodes(backend::train::FunctionMap &codes, + const compiler::train::LoweredTrainableGraph *lowered_graph, + compiler::train::TrainableCodeMap &code_map) +{ + for (auto &&[op_ind, tn_seq] : codes) + { + auto &op = lowered_graph->trainable_graph().operation(op_ind); + const auto backend = lowered_graph->lower_info().operation.at(op_ind); + + assert(code_map.find(op_ind) == code_map.end()); + code_map.insert( + {op_ind, compiler::train::TrainableCodeAndInfo{op_ind, &op, backend, std::move(tn_seq)}}); + } +} + } // namespace } // namespace onert @@ -708,7 +717,6 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( tdata.tgraph = std::move(tgraph); tdata.op_order = std::move(data.op_order); tdata.external_operands = std::move(external_operands); - tdata.operand_layouts = std::move(data.operand_layouts); tdata.custom_kernel_builder = std::move(data.custom_kernel_builder); tdata.is_linear_executor = data.is_linear_executor; tdata.optim_info = training_info.optimizerInfo(); @@ -741,15 +749,17 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( VERBOSE(ExecutorFactory) << "Linearize for backwarding order" << std::endl; Linear::dump(*lowered_graph, backward_order); - for (auto &&pair : tbackend_contexts) + train::TrainableCodeMap code_map; + // Generate tensors and kernels + for (auto &&[backend, context] : tbackend_contexts) { - pair.second->genTensors(); - } + // builtin backend's kernel generator requires access to tensors in other backends. + // So, the other backends must be generated first. + if (backend->config()->id() == "builtin") + continue; - for (auto &&pair : tbackend_contexts) - { - auto tctx = pair.second.get(); - tctx->genTrainingTensors(); + auto fn_map = context->gen(); + generateCodes(fn_map, lowered_graph.get(), code_map); } prepareMigrantTensors(*lowered_graph, tbackend_contexts); @@ -767,6 +777,16 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( } } + // Generate tensors and kernels for only builtin backend + for (auto &&[backend, context] : tbackend_contexts) + { + if (backend->config()->id() == "builtin") + { + auto fn_map = context->gen(); + generateCodes(fn_map, lowered_graph.get(), code_map); + } + } + // Adjust the order of backends for the upcoming iteration auto ordered_contexts = onert::orderBackendContext(tbackend_contexts); @@ -845,22 +865,6 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( })); } - train::TrainableCodeMap code_map; - // Generate kernels - for (auto &&pair : ordered_contexts) - { - auto codes = pair.second->genKernels(); - for (auto &&[op_ind, tn_seq] : codes) - { - auto &op = lowered_graph->trainable_graph().operation(op_ind); - const auto backend = lowered_graph->lower_info().operation.at(op_ind); - - assert(code_map.find(op_ind) == code_map.end()); - code_map.insert( - {op_ind, train::TrainableCodeAndInfo{op_ind, &op, backend, std::move(tn_seq)}}); - } - } - if (order.size() != code_map.size()) { throw std::runtime_error("ExecutorFactory: Some kernels are not generated"); diff --git a/runtime/onert/core/src/compiler/PermuteFactor.cc b/runtime/onert/core/src/compiler/PermuteFactor.cc deleted file mode 100644 index f0081a2a46f..00000000000 --- a/runtime/onert/core/src/compiler/PermuteFactor.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "compiler/PermuteFactor.h" - -#include -#include - -#include "backend/Backend.h" - -std::ostream &operator<<(std::ostream &os, const onert::compiler::PermuteFactor &obj) -{ - assert(obj.backend() && obj.backend()->config()); - return os << "(" << obj.backend()->config()->id() << "/" << to_string(obj.layout()) << ")"; -} diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc index e2224eaf3fc..b9fa3d79aca 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc @@ -16,7 +16,6 @@ #include "ConstantInsertionPass.h" -#include "backend/Backend.h" #include "ir/Graph.h" #include "util/Utils.h" #include "util/logging.h" @@ -31,7 +30,6 @@ namespace pass void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::IOperation &node) { const auto backend = _lowered_graph.lower_info().operation.at(node_index); - const auto factor = PermuteFactor{backend, ir::Layout::NHWC}; for (const auto &input : node.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED) { @@ -42,34 +40,33 @@ void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::I continue; // 1st use of shared constant operand. Keep using original operand without insertion of new one - // Register original operand into keep_operand map for later reuse on same PermuteFactor + // Register original operand into keep_operand map for later reuse on same backend if (_keep_operands_map.find(input) == _keep_operands_map.end()) { - _keep_operands_map.emplace(input, factor); + _keep_operands_map.emplace(input, backend); continue; } // Same PermuteFactor with original operand usage. Keep using original operand - if (_keep_operands_map.at(input) == factor) + if (_keep_operands_map.at(input) == backend) continue; - // Different PermuteFactor with original operand + // Different backend with original operand // Check operand is already created for current input's PermuteFactor // If not, create new operand and register to _replace_operands_map - const auto key = ReplaceKey{input, factor}; - if (_replace_operands_map.count(key) == 0) + if (_replace_operands_map.count(backend) == 0) { ir::Operand new_object(object); new_object.clearDefUse(); const auto new_index = _graph.operands().emplace(new_object); - _replace_operands_map[key] = new_index; + _replace_operands_map[backend] = new_index; } - const auto replaced_input = _replace_operands_map[key]; + const auto replaced_input = _replace_operands_map[backend]; // Update the same inputs of a node at once because inputs of an operation have the same - // PermuteFactor + // backend node.replaceInputs(input, replaced_input); // Update operand @@ -77,7 +74,7 @@ void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::I replaced_object.insertUse(node_index); VERBOSE(ConstInsertPass) << "New operand " << replaced_input << " added(copy of " << input - << ") for " << factor << std::endl; + << ") for " << backend->config()->id() << std::endl; // Remove this node from uses of origin operand // Constant operand has no def. assert(!object.getDef().valid()); diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h index d816240c6c5..0606511e902 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h +++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h @@ -17,11 +17,11 @@ #ifndef __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__ #define __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__ -#include -#include #include "LoweredOperationPass.h" +#include "backend/Backend.h" +#include "ir/Index.h" + #include -#include namespace onert { @@ -42,31 +42,8 @@ class ConstantInsertionPass : public LoweredOperationPass void callback(const ir::OperationIndex &index, ir::IOperation &node) final; private: - struct ReplaceKey - { - ir::OperandIndex index; - PermuteFactor factor; - - bool operator==(const ReplaceKey &other) const - { - return index == other.index && factor == other.factor; - } - }; - - /** - * @brief Structure that provides hash function of ReplaceKey - */ - struct KeyHasher - { - std::size_t operator()(const ReplaceKey &key) const noexcept - { - using std::hash; - return hash()(key.index) ^ (hash()(key.factor) << 1); - } - }; - - std::unordered_map _replace_operands_map; - std::unordered_map _keep_operands_map; + std::unordered_map _replace_operands_map; + std::unordered_map _keep_operands_map; }; } // namespace pass diff --git a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc index 86bacf15a24..108e607ac1b 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc @@ -17,10 +17,9 @@ #include "ConstantLoweringPass.h" #include "backend/Backend.h" -#include -#include -#include +#include "ir/Graph.h" #include "util/logging.h" +#include "util/Utils.h" namespace onert { @@ -40,7 +39,7 @@ void ConstantLoweringPass::callback(const ir::OperationIndex &node_index, ir::IO if (object.isConstant()) { // All constant operand are already assinged at each backend by ContantInsertionPass. So a - // constant has `def` and `use` as the same PermuteFactor + // constant has `def` and `use` as the same backend auto operand_li = std::make_unique(); operand_li->addDefBackend(backend); operand_li->addUseBackend(backend); diff --git a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc index 1448de47354..0e961c62316 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc @@ -41,7 +41,7 @@ void ConstantOutputPass::callback(const ir::OperandIndex &ind, ir::Operand &obj) obj.info().setAsNonConst(); using ir::operation::Permute; - auto permute_obj = std::make_unique(permute_input_ind, ind, Permute::Type::COPY); + auto permute_obj = std::make_unique(permute_input_ind, ind); auto permute_ind = _graph.operations().push(std::move(permute_obj)); permute_input_obj.insertUse(permute_ind); diff --git a/runtime/onert/core/src/compiler/pass/OddOutputPass.cc b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc index e2b3f6111ed..5aabd2aa202 100644 --- a/runtime/onert/core/src/compiler/pass/OddOutputPass.cc +++ b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc @@ -71,7 +71,7 @@ ir::OperandIndex OddOutputPass::insertPermute(ir::OperandIndex ind) auto &output_obj = _graph.operands().at(output_ind); using ir::operation::Permute; - auto permute_obj = std::make_unique(ind, output_ind, Permute::Type::COPY); + auto permute_obj = std::make_unique(ind, output_ind); auto permute_ind = _graph.operations().push(std::move(permute_obj)); output_obj.setDef(permute_ind); diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc index c95d07b421e..68ee497b36e 100644 --- a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc +++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc @@ -150,8 +150,7 @@ ir::OperationIndex PermutationInsertionPass::insertPermute(const ir::OperandInde // Insert permute operation to the graph using Permute = ir::operation::Permute; - auto insert_node = - std::make_unique(operand_index, out_operand_index, Permute::Type::COPY); + auto insert_node = std::make_unique(operand_index, out_operand_index); auto node_index = _graph.operations().push(std::move(insert_node)); diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h index 250cfb4480d..ed3515b07a3 100644 --- a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h +++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h @@ -20,7 +20,6 @@ #include "LoweredOperandPass.h" #include "compiler/BackendManager.h" #include "ir/Operand.h" -#include "compiler/PermuteFactor.h" namespace onert { diff --git a/runtime/onert/core/src/ir/OperationDumper.cc b/runtime/onert/core/src/ir/OperationDumper.cc index 5aa4693adaf..e0f28795b9d 100644 --- a/runtime/onert/core/src/ir/OperationDumper.cc +++ b/runtime/onert/core/src/ir/OperationDumper.cc @@ -268,20 +268,8 @@ void OperationDumper::visit(const Pad &node) void OperationDumper::visit(const Permute &node) { std::string permute_type = "Unknown"; - switch (node.getPermuteType()) - { - case Permute::Type::COPY: - permute_type = "Copy"; - break; - case Permute::Type::NHWC_TO_NCHW: - permute_type = "NHWC to NCHW"; - break; - case Permute::Type::NCHW_TO_NHWC: - permute_type = "NCHW to NHWC"; - break; - } - VERBOSE(LIR) << "* Permute(" + permute_type + ")" << std::endl; + VERBOSE(LIR) << "* " << node.name() << std::endl; VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0) << ")" << std::endl; VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl; } diff --git a/runtime/onert/core/src/ir/operation/Permute.cc b/runtime/onert/core/src/ir/operation/Permute.cc index 813fbaf30ad..77ec42125c7 100644 --- a/runtime/onert/core/src/ir/operation/Permute.cc +++ b/runtime/onert/core/src/ir/operation/Permute.cc @@ -26,8 +26,8 @@ namespace operation void Permute::accept(OperationVisitor &v) const { v.visit(*this); } -Permute::Permute(const OperandIndex &input, const OperandIndex &output, Type type) - : Operation{OperandConstraint::createExact(1u)}, _type{type} +Permute::Permute(const OperandIndex &input, const OperandIndex &output) + : Operation{OperandConstraint::createExact(1u)} { setInputs({input}); setOutputs({output}); diff --git a/runtime/onert/core/src/ir/train/operation/Permute.cc b/runtime/onert/core/src/ir/train/operation/Permute.cc index adc23aa49b7..b1dfcec0336 100644 --- a/runtime/onert/core/src/ir/train/operation/Permute.cc +++ b/runtime/onert/core/src/ir/train/operation/Permute.cc @@ -38,8 +38,7 @@ void Permute::accept(OperationVisitor &v) const { v.visit(*this); } void Permute::accept(TrainableOperationVisitor &v) const { v.visit(*this); } Permute::Permute(const OperationType &operation) - : OperationType{operation.getInputs().at(0), operation.getOutputs().at(0), - operation.getPermuteType()} + : OperationType{operation.getInputs().at(0), operation.getOutputs().at(0)} { // DO NOTHING } diff --git a/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc b/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc index e3472ec51e9..4a6267b0a34 100644 --- a/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc +++ b/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc @@ -332,7 +332,7 @@ operation::Pad generatePad() operation::Permute generatePermute() { - return operation::Permute{OperandIndex{1}, OperandIndex{0}, operation::Permute::Type::COPY}; + return operation::Permute{OperandIndex{1}, OperandIndex{0}}; } operation::Pool2D generatePool2D() diff --git a/runtime/onert/sample/minimal-python/src/minimal.py b/runtime/onert/sample/minimal-python/src/minimal.py index 60e8569b798..2ae3f249fcd 100644 --- a/runtime/onert/sample/minimal-python/src/minimal.py +++ b/runtime/onert/sample/minimal-python/src/minimal.py @@ -1,15 +1,11 @@ -from nnfwapi.libnnfw_api_pybind import * +from onert import infer import sys -def main(nnpackage_path, backends="cpu", operations=""): +def main(nnpackage_path, backends="cpu"): # Create session and load nnpackage - # operations is optional to assign a specific backends to each operation. # The default value of backends is "cpu". - if operations: - session = nnfw_session(nnpackage_path, backends, operations) - else: - session = nnfw_session(nnpackage_path, backends) + session = infer.session(nnpackage_path, backends) # Prepare input. Here we just allocate dummy input arrays. input_size = session.input_size() diff --git a/tests/tools/onert_run/src/args.cc b/tests/tools/onert_run/src/args.cc index dd4857c6efb..f44ed56769f 100644 --- a/tests/tools/onert_run/src/args.cc +++ b/tests/tools/onert_run/src/args.cc @@ -342,18 +342,8 @@ void Args::Parse(const int argc, char **argv) _mem_poll = _arser.get("--mem_poll"); _write_report = _arser.get("--write_report"); - // calling, e.g., "onert_run .. -- shape_prepare .. --shape_run .." should theoretically - // work but allowing both options together on command line makes the usage and implemenation - // of onert_run too complicated. Therefore let's not allow those option together. auto shape_prepare = _arser.get("--shape_prepare"); auto shape_run = _arser.get("--shape_run"); - if (!shape_prepare.empty() && !shape_run.empty()) - { - std::cerr << "Two options '--shape_prepare' and '--shape_run' cannot be given at once" - << std::endl; - exit(1); - } - if (!shape_prepare.empty()) { #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1