blob: e6fdeb912310cb359405db254fb1075052dab6ae [file] [log] [blame]
/* 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 <cstring>
#include "signal/micro/kernels/delay_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.h"
namespace tflite {
namespace {
constexpr int kInputsSize = 1;
constexpr int kOutputsSize = 1;
constexpr int kTensorsSize = kInputsSize + kOutputsSize;
class DelayKernelRunner {
public:
DelayKernelRunner(int* input_dims_data, int16_t* input_data,
int* output_dims_data, int16_t* output_data)
: tensors_{testing::CreateTensor(
input_data, testing::IntArrayFromInts(input_dims_data)),
testing::CreateTensor(
output_data, testing::IntArrayFromInts(output_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_[kInputsSize + 1] = {kInputsSize, 0};
int outputs_array_data_[kOutputsSize + 1] = {kOutputsSize, 1};
TfLiteTensor tensors_[kTensorsSize] = {};
TfLiteIntArray* inputs_array_ = nullptr;
TfLiteIntArray* outputs_array_ = nullptr;
TFLMRegistration* registration_ = tflm_signal::Register_DELAY();
micro::KernelRunner kernel_runner_;
};
void TestDelayInvoke(const int16_t* input_data, int16_t* output_data,
const int16_t* golden, int input_size, int input_num,
micro::KernelRunner* runner, int16_t* input_buffer) {
for (int i = 0; i < input_num; i++) {
memcpy(input_buffer, &input_data[i * input_size],
sizeof(input_data[0]) * input_size);
TF_LITE_MICRO_EXPECT_EQ(runner->Invoke(), kTfLiteOk);
for (int j = 0; j < input_size; ++j) {
TF_LITE_MICRO_EXPECT_EQ(golden[i * input_size + j], output_data[j]);
}
}
}
void TestDelay(int* input_dims_data, const int16_t* input_data,
int* output_dims_data, int16_t* output_data,
const int16_t* golden, int input_size, int input_num,
const unsigned char* flexbuffers_data,
const unsigned int flexbuffers_data_size,
int16_t* input_buffer) {
DelayKernelRunner delay_runner(input_dims_data, input_buffer,
output_dims_data, output_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.
TF_LITE_MICRO_EXPECT_EQ(delay_runner.kernel_runner().InitAndPrepare(
reinterpret_cast<const char*>(flexbuffers_data),
flexbuffers_data_size),
kTfLiteOk);
TestDelayInvoke(input_data, output_data, golden, input_size, input_num,
&delay_runner.kernel_runner(), input_buffer);
}
// TestDelayReset() runs a test with the given inputs twice with a reset with
// the main purpose of testing the Delay's Reset functionality. If you just
// want to make sure Delay's Op output matches a set of golden values for an
// input use TestDelay() instead.
void TestDelayReset(int* input_dims_data, const int16_t* input_data,
int* output_dims_data, int16_t* output_data,
const int16_t* golden, int input_size, int input_num,
const unsigned char* flexbuffers_data,
const unsigned int flexbuffers_data_size,
int16_t* input_buffer) {
DelayKernelRunner delay_runner(input_dims_data, input_buffer,
output_dims_data, output_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.
TF_LITE_MICRO_EXPECT_EQ(delay_runner.kernel_runner().InitAndPrepare(
reinterpret_cast<const char*>(flexbuffers_data),
flexbuffers_data_size),
kTfLiteOk);
TestDelayInvoke(input_data, output_data, golden, input_size, input_num,
&delay_runner.kernel_runner(), input_buffer);
delay_runner.kernel_runner().Reset();
TestDelayInvoke(input_data, output_data, golden, input_size, input_num,
&delay_runner.kernel_runner(), input_buffer);
}
} // namespace
} // namespace tflite
TF_LITE_MICRO_TESTS_BEGIN
TF_LITE_MICRO_TEST(DelayTestSingleDimDelayLessThanFrameSize) {
const int kInputSize = 8;
const int kInputNum = 2;
int input_shape[] = {1, kInputSize};
int output_shape[] = {1, kInputSize};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The input data. Gets copied to input_buffer kInputNum times.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
const int16_t golden[kInputNum * kInputSize] = {0x0, 0x0, 0x0, 0x1, 0x2, 0x3,
0x4, 0x5, 0x6, 0x7, 0x8, 0x0,
0x0, 0x0, 0x0, 0x0};
tflite::TestDelay(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_3_delay,
g_gen_data_size_3_delay, input_buffer);
}
TF_LITE_MICRO_TEST(DelayTestSingleDimDelayGreaterThanFrameSize) {
const int kInputSize = 3;
const int kInputNum = 3;
int input_shape[] = {1, kInputSize};
int output_shape[] = {1, kInputSize};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The input data. Gets copied to input_buffer kInputNum times.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
const int16_t golden[kInputNum * kInputSize] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4,
};
tflite::TestDelay(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_5_delay,
g_gen_data_size_5_delay, input_buffer);
}
TF_LITE_MICRO_TEST(DelayTestMultiDimDelayLessThanFrameSize) {
const int kInputSize = 16;
const int kInputNum = 2;
int input_shape[] = {2, 4, 4};
int output_shape[] = {2, 4, 4};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The op will be invoked 2 times (Input X, X=0,1)
// For each invocation, the input's shape is (4, 4) but flattened for clarity
// On each invocation, the input data is copied to input_buffer first.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB,
0xC, 0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
// For each invocation, we expect the following output (Output X, X=0,1)
// Each time, the output's shape is (4, 4) but flattened for clarity
const int16_t golden[kInputNum * kInputSize] = {
// Output 0
0x0,
0x0,
0x0,
0x1,
0x0,
0x0,
0x0,
0x5,
0x0,
0x0,
0x0,
0x9,
0x0,
0x0,
0x0,
0xD,
// Output 1
0x2,
0x3,
0x4,
0x0,
0x6,
0x7,
0x8,
0x0,
0xA,
0xB,
0xC,
0x0,
0xE,
0xF,
0x0,
0x0,
};
tflite::TestDelay(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_3_delay,
g_gen_data_size_3_delay, input_buffer);
}
TF_LITE_MICRO_TEST(DelayTestMultiDimDelayGreaterThanFrameSize) {
const int kInputSize = 16;
const int kInputNum = 3;
int input_shape[] = {2, 4, 4};
int output_shape[] = {2, 4, 4};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The op will be invoked 3 times (Input X, X=0,1,2)
// For each invocation, the input's shape is (4, 4) but flattened for clarity
// On each invocation, the input data is copied to input_buffer first.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC,
0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
// For each invocation, we expect the following output (Output X, X=0,1,2)
// Each time, the output's shape is (4, 4) but flattened for clarity
const int16_t golden[kInputNum * kInputSize] = {
// Output 0
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
// Output 1
0x0,
0x1,
0x2,
0x3,
0x0,
0x5,
0x6,
0x7,
0x0,
0x9,
0xA,
0xB,
0x0,
0xD,
0xE,
0xF,
// Output 2
0x4,
0x0,
0x0,
0x0,
0x8,
0x0,
0x0,
0x0,
0xC,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
};
tflite::TestDelay(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_5_delay,
g_gen_data_size_5_delay, input_buffer);
}
TF_LITE_MICRO_TEST(DelayTestResetSingleDimDelayLessThanFrameSize) {
const int kInputSize = 8;
const int kInputNum = 2;
int input_shape[] = {1, kInputSize};
int output_shape[] = {1, kInputSize};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The input data. Gets copied to input_buffer kInputNum times.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
const int16_t golden[kInputNum * kInputSize] = {0x0, 0x0, 0x0, 0x1, 0x2, 0x3,
0x4, 0x5, 0x6, 0x7, 0x8, 0x0,
0x0, 0x0, 0x0, 0x0};
tflite::TestDelayReset(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_3_delay,
g_gen_data_size_3_delay, input_buffer);
}
TF_LITE_MICRO_TEST(DelayTestResetSingleResetDimDelayGreaterThanFrameSize) {
const int kInputSize = 3;
const int kInputNum = 3;
int input_shape[] = {1, kInputSize};
int output_shape[] = {1, kInputSize};
// The buffer that gets passed to the model.
int16_t input_buffer[kInputSize];
// The input data. Gets copied to input_buffer kInputNum times.
const int16_t input[kInputNum * kInputSize] = {
0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0,
};
int16_t output[kInputNum * kInputSize] = {0};
const int16_t golden[kInputNum * kInputSize] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4,
};
tflite::TestDelayReset(input_shape, input, output_shape, output, golden,
kInputSize, kInputNum, g_gen_data_5_delay,
g_gen_data_size_5_delay, input_buffer);
}
TF_LITE_MICRO_TESTS_END