mirror of
https://github.com/vee1e/tflite-micro.git
synced 2026-09-03 18:58:00 +00:00
247 lines
9.2 KiB
C++
247 lines
9.2 KiB
C++
/* Copyright 2025 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 <array>
|
|
#include <cstdint>
|
|
#include <initializer_list>
|
|
|
|
#include "tensorflow/lite/core/c/common.h"
|
|
#include "tensorflow/lite/micro/kernels/decode_state.h"
|
|
#include "tensorflow/lite/micro/kernels/decode_test_helpers.h"
|
|
#include "tensorflow/lite/micro/testing/micro_test_v2.h"
|
|
|
|
namespace {
|
|
|
|
//
|
|
// LUT test data
|
|
//
|
|
constexpr int kBitWidthLUT = 2;
|
|
|
|
constexpr int8_t kAncillaryDataLUT0[] = {1, 2, 3, 4};
|
|
constexpr int16_t kAncillaryDataLUT1[] = {5, 6, 7, 8};
|
|
|
|
constexpr uint8_t kDcmLUT0[tflite::DecodeState::kDcmSizeInBytes] = {
|
|
tflite::DecodeState::kDcmTypeLUT, // type: LUT
|
|
1, // DCM version: 1
|
|
0, // reserved
|
|
0, // reserved
|
|
1, // LUT version: 1
|
|
kBitWidthLUT, // Parameters: bit-width 2
|
|
std::size(kAncillaryDataLUT0), // channel stride
|
|
};
|
|
|
|
constexpr uint8_t kDcmLUT1[tflite::DecodeState::kDcmSizeInBytes] = {
|
|
tflite::DecodeState::kDcmTypeLUT, // type: LUT
|
|
1, // DCM version: 1
|
|
0, // reserved
|
|
0, // reserved
|
|
1, // LUT version: 1
|
|
kBitWidthLUT, // Parameters: bit-width 2
|
|
std::size(kAncillaryDataLUT1), // channel stride
|
|
};
|
|
|
|
// Align the tensor data the same as a Buffer in the TfLite schema.
|
|
// The encoded bitstring consists of fixed bit width groups (indices), each
|
|
// group representing an offset into the <value_table> (kAncillaryDataLUTx). The
|
|
// bitstring is in big-endian byte order with the most significant bit first. A
|
|
// bitstring is padded on the end, to the next byte boundary, with zero bits.
|
|
alignas(16) const uint8_t kEncodedLUT[] = {0x1B, 0xE4};
|
|
|
|
// Tensor shapes as TfLiteIntArray
|
|
constexpr int kOutputShapeLUT[] = {3, 1, 2, 4};
|
|
constexpr int kEncodedShapeLUT[] = {1, sizeof(kEncodedLUT)};
|
|
|
|
constexpr int8_t kExpectLUT0[] = {1, 2, 3, 4, 4, 3, 2, 1};
|
|
constexpr int16_t kExpectLUT1[] = {5, 6, 7, 8, 8, 7, 6, 5};
|
|
|
|
} // namespace
|
|
|
|
using tflite::testing::AncillaryData;
|
|
using tflite::testing::TensorInDatum;
|
|
using tflite::testing::TensorOutDatum;
|
|
|
|
TEST(DecodeTest, DecodeSingleTensorLUT) {
|
|
// Align the tensor data the same as a Buffer in the TfLite schema
|
|
alignas(16) int8_t output_data[std::size(kExpectLUT0)] = {};
|
|
alignas(16) const AncillaryData<int8_t, std::size(kAncillaryDataLUT0)>
|
|
kAncillaryData = {{kDcmLUT0}, {kAncillaryDataLUT0}};
|
|
|
|
constexpr int kAncillaryShapeLUT[] = {1, sizeof(kAncillaryData)};
|
|
|
|
const TfLiteIntArray* const encoded_dims =
|
|
tflite::testing::IntArrayFromInts(kEncodedShapeLUT);
|
|
static const TensorInDatum tid_encode = {
|
|
kEncodedLUT,
|
|
*encoded_dims,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> encodes = {
|
|
&tid_encode,
|
|
};
|
|
|
|
const TfLiteIntArray* const ancillary_dims =
|
|
tflite::testing::IntArrayFromInts(kAncillaryShapeLUT);
|
|
static const TensorInDatum tid_ancillary = {
|
|
&kAncillaryData,
|
|
*ancillary_dims,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> ancillaries = {
|
|
&tid_ancillary};
|
|
|
|
const TfLiteIntArray* const output_dims =
|
|
tflite::testing::IntArrayFromInts(kOutputShapeLUT);
|
|
constexpr int kOutputZeroPointsData[] = {0};
|
|
const TfLiteIntArray* const kOutputZeroPoints =
|
|
tflite::testing::IntArrayFromInts(kOutputZeroPointsData);
|
|
const TfLiteFloatArray kOutputScales = {kOutputZeroPoints->size};
|
|
static const TensorOutDatum tod = {
|
|
output_data, *output_dims, kTfLiteInt8, kOutputScales, *kOutputZeroPoints,
|
|
0, {},
|
|
};
|
|
static constexpr std::initializer_list<const TensorOutDatum*> outputs = {
|
|
&tod};
|
|
|
|
const std::initializer_list<const void*> expected = {kExpectLUT0};
|
|
|
|
tflite::testing::TestDecode<encodes.size() + ancillaries.size(),
|
|
outputs.size()>(
|
|
encodes, ancillaries, outputs, expected, tflite::Register_DECODE());
|
|
}
|
|
|
|
TEST(DecodeTest, DecodeTwoTensorsLUT) {
|
|
// Align the tensor data the same as a Buffer in the TfLite schema
|
|
alignas(16) int8_t output_data0[std::size(kExpectLUT0)] = {};
|
|
alignas(16) int16_t output_data1[std::size(kExpectLUT1)] = {};
|
|
alignas(16) const AncillaryData<int8_t, std::size(kAncillaryDataLUT0)>
|
|
kAncillaryData0 = {{kDcmLUT0}, {kAncillaryDataLUT0}};
|
|
alignas(16) const AncillaryData<int16_t, std::size(kAncillaryDataLUT1)>
|
|
kAncillaryData1 = {{kDcmLUT1}, {kAncillaryDataLUT1}};
|
|
|
|
constexpr int kAncillaryShapeLUT0[] = {1, sizeof(kAncillaryData0)};
|
|
constexpr int kAncillaryShapeLUT1[] = {1, sizeof(kAncillaryData1)};
|
|
|
|
const TfLiteIntArray* const encoded_dims =
|
|
tflite::testing::IntArrayFromInts(kEncodedShapeLUT);
|
|
static const TensorInDatum tid_encode0 = {
|
|
kEncodedLUT,
|
|
*encoded_dims,
|
|
};
|
|
static const TensorInDatum tid_encode1 = {
|
|
kEncodedLUT,
|
|
*encoded_dims,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> encodes = {
|
|
&tid_encode0, &tid_encode1};
|
|
|
|
const TfLiteIntArray* const ancillary_dims0 =
|
|
tflite::testing::IntArrayFromInts(kAncillaryShapeLUT0);
|
|
static const TensorInDatum tid_ancillary0 = {
|
|
&kAncillaryData0,
|
|
*ancillary_dims0,
|
|
};
|
|
const TfLiteIntArray* const ancillary_dims1 =
|
|
tflite::testing::IntArrayFromInts(kAncillaryShapeLUT1);
|
|
static const TensorInDatum tid_ancillary1 = {
|
|
&kAncillaryData1,
|
|
*ancillary_dims1,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> ancillaries = {
|
|
&tid_ancillary0, &tid_ancillary1};
|
|
|
|
const TfLiteIntArray* const output_dims =
|
|
tflite::testing::IntArrayFromInts(kOutputShapeLUT);
|
|
constexpr int kOutputZeroPointsData[] = {1, 0};
|
|
const TfLiteIntArray* const kOutputZeroPoints =
|
|
tflite::testing::IntArrayFromInts(kOutputZeroPointsData);
|
|
const TfLiteFloatArray kOutputScales = {kOutputZeroPoints->size};
|
|
static const TensorOutDatum tod0 = {
|
|
output_data0,
|
|
*output_dims,
|
|
kTfLiteInt8,
|
|
kOutputScales,
|
|
*kOutputZeroPoints,
|
|
0,
|
|
{},
|
|
};
|
|
static const TensorOutDatum tod1 = {
|
|
output_data1,
|
|
*output_dims,
|
|
kTfLiteInt16,
|
|
kOutputScales,
|
|
*kOutputZeroPoints,
|
|
0,
|
|
{},
|
|
};
|
|
static constexpr std::initializer_list<const TensorOutDatum*> outputs = {
|
|
&tod0, &tod1};
|
|
|
|
const std::initializer_list<const void*> expected = {kExpectLUT0,
|
|
kExpectLUT1};
|
|
|
|
tflite::testing::TestDecode<encodes.size() + ancillaries.size(),
|
|
outputs.size()>(
|
|
encodes, ancillaries, outputs, expected, tflite::Register_DECODE());
|
|
}
|
|
|
|
TEST(DecodeTest, DecodeWithAltDecompressionMemory) {
|
|
// Align the tensor data the same as a Buffer in the TfLite schema
|
|
alignas(16) int8_t output_data[std::size(kExpectLUT0)] = {};
|
|
alignas(16) const AncillaryData<int8_t, std::size(kAncillaryDataLUT0)>
|
|
kAncillaryData = {{kDcmLUT0}, {kAncillaryDataLUT0}};
|
|
|
|
constexpr int kAncillaryShapeLUT[] = {1, sizeof(kAncillaryData)};
|
|
|
|
const TfLiteIntArray* const encoded_dims =
|
|
tflite::testing::IntArrayFromInts(kEncodedShapeLUT);
|
|
static const TensorInDatum tid_encode = {
|
|
kEncodedLUT,
|
|
*encoded_dims,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> encodes = {
|
|
&tid_encode,
|
|
};
|
|
|
|
const TfLiteIntArray* const ancillary_dims =
|
|
tflite::testing::IntArrayFromInts(kAncillaryShapeLUT);
|
|
static const TensorInDatum tid_ancillary = {
|
|
&kAncillaryData,
|
|
*ancillary_dims,
|
|
};
|
|
static constexpr std::initializer_list<const TensorInDatum*> ancillaries = {
|
|
&tid_ancillary};
|
|
|
|
const TfLiteIntArray* const output_dims =
|
|
tflite::testing::IntArrayFromInts(kOutputShapeLUT);
|
|
constexpr int kOutputZeroPointsData[] = {0};
|
|
const TfLiteIntArray* const kOutputZeroPoints =
|
|
tflite::testing::IntArrayFromInts(kOutputZeroPointsData);
|
|
const TfLiteFloatArray kOutputScales = {kOutputZeroPoints->size};
|
|
static const TensorOutDatum tod = {
|
|
nullptr, // using alternate decompression memory
|
|
*output_dims, kTfLiteInt8, kOutputScales, *kOutputZeroPoints, 0, {},
|
|
};
|
|
static constexpr std::initializer_list<const TensorOutDatum*> outputs = {
|
|
&tod};
|
|
|
|
const std::initializer_list<const void*> expected = {kExpectLUT0};
|
|
|
|
std::initializer_list<tflite::MicroContext::AlternateMemoryRegion> amr = {
|
|
{output_data, sizeof(output_data)}};
|
|
|
|
tflite::testing::TestDecode<encodes.size() + ancillaries.size(),
|
|
outputs.size()>(
|
|
encodes, ancillaries, outputs, expected, tflite::Register_DECODE(), &amr);
|
|
}
|
|
|
|
TF_LITE_MICRO_TESTS_MAIN
|