mirror of
https://github.com/vee1e/tflite-micro.git
synced 2026-09-02 18:27:52 +00:00
241 lines
9.8 KiB
C++
241 lines
9.8 KiB
C++
/* Copyright 2021 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.
|
|
==============================================================================*/
|
|
|
|
#include <cstdint>
|
|
|
|
#include "signal/micro/kernels/stacker_flexbuffers_generated_data.h"
|
|
#include "tensorflow/lite/micro/kernels/kernel_runner.h"
|
|
#include "tensorflow/lite/micro/test_helpers.h"
|
|
#include "tensorflow/lite/micro/testing/micro_test_v2.h"
|
|
|
|
namespace tflite {
|
|
namespace {
|
|
|
|
constexpr int kInputsSize = 1;
|
|
constexpr int kOutputsSize = 2;
|
|
constexpr int kTensorsSize = kInputsSize + kOutputsSize;
|
|
|
|
class StackerKernelRunner {
|
|
public:
|
|
StackerKernelRunner(int* input_dims_data, const int16_t* input_data,
|
|
int* output_dims_data, int16_t* output_data,
|
|
int* output_ready_dims_data, bool* ouput_ready_data)
|
|
: tensors_{testing::CreateTensor(
|
|
input_data,
|
|
tflite::testing::IntArrayFromInts(input_dims_data)),
|
|
testing::CreateTensor(
|
|
output_data,
|
|
tflite::testing::IntArrayFromInts(output_dims_data)),
|
|
testing::CreateTensor(
|
|
ouput_ready_data,
|
|
testing::IntArrayFromInts(output_ready_dims_data))},
|
|
inputs_array_{testing::IntArrayFromInts(inputs_array_data_)},
|
|
outputs_array_{testing::IntArrayFromInts(outputs_array_data_)},
|
|
kernel_runner_{*registration_, tensors_, kTensorsSize,
|
|
inputs_array_, outputs_array_, nullptr} {}
|
|
|
|
micro::KernelRunner* kernel_runner() { return &kernel_runner_; }
|
|
|
|
private:
|
|
int inputs_array_data_[2] = {1, 0};
|
|
int outputs_array_data_[3] = {2, 1, 2};
|
|
TfLiteTensor tensors_[kTensorsSize] = {};
|
|
TfLiteIntArray* inputs_array_ = nullptr;
|
|
TfLiteIntArray* outputs_array_ = nullptr;
|
|
TFLMRegistration* registration_ = tflm_signal::Register_STACKER();
|
|
micro::KernelRunner kernel_runner_;
|
|
};
|
|
|
|
void TestStackerInvoke(int* output_dims_data, int16_t* output_data,
|
|
bool* ouput_ready_data, const int16_t* golden,
|
|
micro::KernelRunner* kernel_runner) {
|
|
TfLiteIntArray* output_dims = testing::IntArrayFromInts(output_dims_data);
|
|
|
|
const int output_len = ElementCount(*output_dims);
|
|
|
|
EXPECT_EQ(kernel_runner->Invoke(), kTfLiteOk);
|
|
EXPECT_EQ(*ouput_ready_data, 1);
|
|
|
|
for (int i = 0; i < output_len; ++i) {
|
|
EXPECT_EQ(golden[i], output_data[i]);
|
|
}
|
|
}
|
|
|
|
void TestStacker(int* input_dims_data, const int16_t* input_data,
|
|
int* output_dims_data, int16_t* output_data,
|
|
int* output_ready_dims_data, bool* ouput_ready_data,
|
|
const int16_t* golden, const unsigned char* flexbuffers_data,
|
|
const unsigned int flexbuffers_data_size) {
|
|
StackerKernelRunner stacker_runner(input_dims_data, input_data,
|
|
output_dims_data, output_data,
|
|
output_ready_dims_data, ouput_ready_data);
|
|
|
|
// TfLite uses a char* for the raw bytes whereas flexbuffers use an unsigned
|
|
// char*. This small discrepancy results in compiler warnings unless we
|
|
// reinterpret_cast right before passing in the flexbuffer bytes to the
|
|
// KernelRunner.
|
|
EXPECT_EQ(stacker_runner.kernel_runner()->InitAndPrepare(
|
|
reinterpret_cast<const char*>(flexbuffers_data),
|
|
flexbuffers_data_size),
|
|
kTfLiteOk);
|
|
TestStackerInvoke(output_dims_data, output_data, ouput_ready_data, golden,
|
|
stacker_runner.kernel_runner());
|
|
}
|
|
|
|
// TestStackerReset() runs a test with the given inputs twice with a reset with
|
|
// the main purpose of testing the Stacker's Reset functionality. If you just
|
|
// want to make sure Stacker's Op output matches a set of golden values for an
|
|
// input use TestStacker() instead.
|
|
void TestStackerReset(int* input_dims_data, const int16_t* input_data,
|
|
int* output_dims_data, int16_t* output_data,
|
|
int* output_ready_dims_data, bool* ouput_ready_data,
|
|
const int16_t* golden,
|
|
const unsigned char* flexbuffers_data,
|
|
const unsigned int flexbuffers_data_size) {
|
|
StackerKernelRunner stacker_runner(input_dims_data, input_data,
|
|
output_dims_data, output_data,
|
|
output_ready_dims_data, ouput_ready_data);
|
|
|
|
// TfLite uses a char* for the raw bytes whereas flexbuffers use an unsigned
|
|
// char*. This small discrepancy results in compiler warnings unless we
|
|
// reinterpret_cast right before passing in the flexbuffer bytes to the
|
|
// KernelRunner.
|
|
EXPECT_EQ(stacker_runner.kernel_runner()->InitAndPrepare(
|
|
reinterpret_cast<const char*>(flexbuffers_data),
|
|
flexbuffers_data_size),
|
|
kTfLiteOk);
|
|
TestStackerInvoke(output_dims_data, output_data, ouput_ready_data, golden,
|
|
stacker_runner.kernel_runner());
|
|
stacker_runner.kernel_runner()->Reset();
|
|
TestStackerInvoke(output_dims_data, output_data, ouput_ready_data, golden,
|
|
stacker_runner.kernel_runner());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace tflite
|
|
|
|
TEST(StackerTest, StackerTest3ChannelStep1) {
|
|
int input_shape[] = {1, 3};
|
|
int output_shape[] = {1, 6};
|
|
int output_ready_shape[] = {0};
|
|
const int16_t input[] = {0x1234, 0x5678, 0x4321};
|
|
const int16_t golden[] = {0x1234, 0x5678, 0x4321, 0x1234, 0x5678, 0x4321};
|
|
|
|
int16_t output[6];
|
|
bool output_ready = false;
|
|
|
|
tflite::TestStacker(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_3_channels_step_1,
|
|
g_gen_data_size_stacker_3_channels_step_1);
|
|
}
|
|
|
|
TEST(StackerTest, StackerTest10ChannelStep2_1stTest) {
|
|
int input_shape[] = {1, 10};
|
|
int output_shape[] = {1, 20};
|
|
int output_ready_shape[] = {0};
|
|
|
|
int16_t output[20];
|
|
bool output_ready = false;
|
|
|
|
const int16_t input[10] = {252, 477, 1071, 166, 1022,
|
|
312, 1171, 1586, 1491, 145};
|
|
|
|
const int16_t golden[] = {252, 477, 1071, 166, 1022, 312, 1171,
|
|
1586, 1491, 145, 252, 477, 1071, 166,
|
|
1022, 312, 1171, 1586, 1491, 145};
|
|
tflite::TestStacker(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_10_channels_step_2,
|
|
g_gen_data_size_stacker_10_channels_step_2);
|
|
}
|
|
|
|
TEST(StackerTest, StackerTest10ChannelStep2_2ndTest) {
|
|
int input_shape[] = {1, 10};
|
|
int output_shape[] = {1, 20};
|
|
int output_ready_shape[] = {0};
|
|
|
|
int16_t output[20];
|
|
bool output_ready = false;
|
|
|
|
const int16_t input[10] = {1060, 200, 69, 1519, 883,
|
|
1317, 182, 724, 143, 334};
|
|
|
|
const int16_t golden[] = {1060, 200, 69, 1519, 883, 1317, 182, 724, 143, 334,
|
|
1060, 200, 69, 1519, 883, 1317, 182, 724, 143, 334};
|
|
|
|
tflite::TestStacker(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_10_channels_step_2,
|
|
g_gen_data_size_stacker_10_channels_step_2);
|
|
}
|
|
|
|
TEST(StackerTest, StackerTestReset3ChannelStep1) {
|
|
int input_shape[] = {1, 3};
|
|
int output_shape[] = {1, 6};
|
|
int output_ready_shape[] = {0};
|
|
const int16_t input[] = {0x1234, 0x5678, 0x4321};
|
|
const int16_t golden[] = {0x1234, 0x5678, 0x4321, 0x1234, 0x5678, 0x4321};
|
|
|
|
int16_t output[6];
|
|
bool output_ready = false;
|
|
|
|
tflite::TestStackerReset(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_3_channels_step_1,
|
|
g_gen_data_size_stacker_3_channels_step_1);
|
|
}
|
|
|
|
TEST(StackerTest, StackerTestReset10ChannelStep2_1stTest) {
|
|
int input_shape[] = {1, 10};
|
|
int output_shape[] = {1, 20};
|
|
int output_ready_shape[] = {0};
|
|
|
|
int16_t output[20];
|
|
bool output_ready = false;
|
|
|
|
const int16_t input[10] = {252, 477, 1071, 166, 1022,
|
|
312, 1171, 1586, 1491, 145};
|
|
|
|
const int16_t golden[] = {252, 477, 1071, 166, 1022, 312, 1171,
|
|
1586, 1491, 145, 252, 477, 1071, 166,
|
|
1022, 312, 1171, 1586, 1491, 145};
|
|
tflite::TestStackerReset(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_10_channels_step_2,
|
|
g_gen_data_size_stacker_10_channels_step_2);
|
|
}
|
|
|
|
TEST(StackerTest, StackerTestReset10ChannelStep2_2ndTest) {
|
|
int input_shape[] = {1, 10};
|
|
int output_shape[] = {1, 20};
|
|
int output_ready_shape[] = {0};
|
|
|
|
int16_t output[20];
|
|
bool output_ready = false;
|
|
|
|
const int16_t input[10] = {1060, 200, 69, 1519, 883,
|
|
1317, 182, 724, 143, 334};
|
|
|
|
const int16_t golden[] = {1060, 200, 69, 1519, 883, 1317, 182, 724, 143, 334,
|
|
1060, 200, 69, 1519, 883, 1317, 182, 724, 143, 334};
|
|
|
|
tflite::TestStackerReset(input_shape, input, output_shape, output,
|
|
output_ready_shape, &output_ready, golden,
|
|
g_gen_data_stacker_10_channels_step_2,
|
|
g_gen_data_size_stacker_10_channels_step_2);
|
|
}
|
|
|
|
TF_LITE_MICRO_TESTS_MAIN
|