Files
tensorflow--tensorflow/tensorflow/lite/kernels/embedding_lookup_test.cc
T
wehub-resource-sync 8a852e4b4e
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:14:16 +08:00

1114 lines
42 KiB
C++

/* 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.
==============================================================================*/
// Unit test for TFLite Lookup op.
#include <stdint.h>
#include <functional>
#include <initializer_list>
#include <memory>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/lite/core/interpreter.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/test_util.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/types/half.h"
namespace tflite {
namespace {
constexpr float kTestTolerance = 7.41e-03;
constexpr float kFp16TestTolerance = 1e-02;
using ::testing::ElementsAreArray;
class BaseEmbeddingLookupOpModel : public SingleOpModel {
public:
BaseEmbeddingLookupOpModel(
std::initializer_list<int> index_shape,
std::initializer_list<int> weight_shape,
TensorType weight_type = TensorType_FLOAT32,
TensorType output_type = TensorType_FLOAT32,
const std::vector<float>& per_channel_quantization_scales = {},
int blocksize = 0) {
input_ = AddInput(TensorType_INT32);
if (per_channel_quantization_scales.empty()) {
weight_ = AddInput(weight_type);
} else {
std::vector<int64_t> per_channel_quantization_offsets(
per_channel_quantization_scales.size(), 0);
weight_ = AddInput({/*type=*/weight_type,
/*shape=*/weight_shape,
/*min=*/0.0f,
/*max=*/0.0f,
/*scale=*/0.0f,
/*zero_point=*/0,
/*per_channel_quantization=*/true,
per_channel_quantization_scales,
per_channel_quantization_offsets,
/*channel_index=*/0,
/*traversal_order=*/{},
/*format=*/{},
/*block_size=*/{},
/*block_map=*/{},
/*shape_signature=*/{},
/*per_block_quantization=*/blocksize});
}
output_ = AddOutput(output_type);
SetBuiltinOp(BuiltinOperator_EMBEDDING_LOOKUP, BuiltinOptions_NONE, 0);
BuildInterpreter({index_shape, weight_shape});
}
void SetInput(std::initializer_list<int> data) {
PopulateTensor(input_, data);
}
template <typename T>
std::vector<T> GetOutput() {
return ExtractVector<T>(output_);
}
protected:
int input_;
int weight_;
int output_;
};
class EmbeddingLookupOpModel : public BaseEmbeddingLookupOpModel {
public:
using BaseEmbeddingLookupOpModel::BaseEmbeddingLookupOpModel;
template <typename T>
void Set3DWeightMatrix(const std::function<T(int, int, int)>& function) {
TfLiteTensor* tensor = interpreter_->tensor(weight_);
int rows = tensor->dims->data[0];
int columns = tensor->dims->data[1];
int features = tensor->dims->data[2];
T* data = GetTensorData<T>(tensor);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
for (int k = 0; k < features; k++) {
data[(i * columns + j) * features + k] = function(i, j, k);
}
}
}
}
template <typename T>
void Set2DWeightMatrix(const std::function<T(int, int)>& function) {
TfLiteTensor* tensor = interpreter_->tensor(weight_);
int64_t rows = tensor->dims->data[0];
int64_t columns = tensor->dims->data[1];
T* data = GetTensorData<T>(tensor);
for (int64_t i = 0; i < rows; i++) {
for (int64_t j = 0; j < columns; j++) {
data[i * columns + j] = function(i, j);
}
}
}
};
class HybridEmbeddingLookupOpModel : public BaseEmbeddingLookupOpModel {
public:
HybridEmbeddingLookupOpModel(std::initializer_list<int> index_shape,
std::initializer_list<int> weight_shape,
TensorType weight_type,
TensorType output_type = TensorType_FLOAT32)
: BaseEmbeddingLookupOpModel(index_shape, weight_shape, weight_type,
output_type) {}
void SetWeight(std::initializer_list<float> data) {
SymmetricQuantizeAndPopulate(weight_, data);
}
void SetSignedWeight(std::initializer_list<float> data) {
SignedSymmetricQuantizeAndPopulate(weight_, data);
}
};
class PerAxisHybridEmbeddingLookupOpModel : public BaseEmbeddingLookupOpModel {
public:
PerAxisHybridEmbeddingLookupOpModel(
std::initializer_list<int> index_shape,
std::initializer_list<int> weight_shape,
const std::vector<float>& per_channel_quantization_scales,
TensorType weights_type, TensorType output_type = TensorType_FLOAT32)
: BaseEmbeddingLookupOpModel(index_shape, weight_shape, weights_type,
output_type,
per_channel_quantization_scales) {}
void SetSignedWeight(std::initializer_list<float> data) {
PerChannelSymmetricQuantizeAndPopulate(weight_, data);
}
};
class PerBlockHybridEmbeddingLookupOpModel : public BaseEmbeddingLookupOpModel {
public:
PerBlockHybridEmbeddingLookupOpModel(
std::initializer_list<int> index_shape,
std::initializer_list<int> weight_shape, TensorType weights_type,
int blocksize, std::vector<float> scales,
TensorType output_type = TensorType_FLOAT32)
: BaseEmbeddingLookupOpModel(index_shape, weight_shape, weights_type,
output_type, scales, blocksize) {}
void SetSignedWeight(std::initializer_list<float> data) {
PerBlockSymmetricQuantizeAndPopulate(weight_, data);
}
};
// TODO(ahentz): write more tests that exercise the details of the op, such as
// lookup errors and variable input shapes.
TEST(EmbeddingLookupOpTest, Float32) {
EmbeddingLookupOpModel m({3}, {3, 2, 4}, TensorType_FLOAT32,
TensorType_FLOAT32);
m.SetInput({1, 0, 2});
m.Set3DWeightMatrix<float>(
[](int i, int j, int k) -> float { return i + j / 10.0f + k / 100.0f; });
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear({
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
})));
}
TEST(EmbeddingLookupOpTest, Float16) {
EmbeddingLookupOpModel m({3}, {3, 2, 4}, TensorType_FLOAT16,
TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.Set3DWeightMatrix<half>(
[](int i, int j, int k) -> half { return i + j / 10.0f + k / 100.0f; });
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
#if !defined(MEMORY_SANITIZER) && !defined(GOOGLE_UNSUPPORTED_OS_LOONIX) && \
defined(__LP64__)
TEST(EmbeddingLookupOpTest, LargeTableTest) {
EmbeddingLookupOpModel m({1}, {256000, 9216});
// Choose a value specifically designed to overflow int32.max
m.SetInput({235248});
m.Set2DWeightMatrix<float>(
[](int i, int j) -> float { return j + i / 100.; });
// This will cause a lookup at index 235248 in a buffer where every row
// has 9216 entries * 4 bytes per entry, which will overflow unless
// the Op is using a 64-bit offset for address calculation.
ASSERT_EQ(m.Invoke(), kTfLiteOk);
std::vector<float> exp(9216);
for (int s = 0; s < exp.size(); s++) {
exp[s] = static_cast<float>(s) + 2352.48f;
}
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(exp)));
}
#endif
TEST(HybridEmbeddingLookupHybridOpTest, Simple2DTestUint8) {
HybridEmbeddingLookupOpModel m({3}, {3, 8}, TensorType_UINT8);
m.SetInput({1, 0, 2});
m.SetWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple3DTestUint8) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 4}, TensorType_UINT8);
m.SetInput({1, 0, 2});
m.SetWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple4DTestUint8) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, TensorType_UINT8);
m.SetInput({1, 0, 2});
m.SetWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple4DTestUint8Float16) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, TensorType_UINT8,
TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, 1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kFp16TestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple2DTestInt8) {
HybridEmbeddingLookupOpModel m({3}, {3, 8}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple3DTestInt8) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 4}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple4DTestInt8) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(HybridEmbeddingLookupHybridOpTest, Simple4DTestInt8Float16) {
HybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, TensorType_INT8,
TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kFp16TestTolerance)));
}
TEST(EmbeddingLookupHybridOpTest, Simple3DTestQuantized) {
EmbeddingLookupOpModel m({3}, {3, 2, 4}, TensorType_UINT8, TensorType_INT8);
m.SetInput({1, 0, 2});
m.Set3DWeightMatrix<uint8_t>(
[](int i, int j, int k) -> uint8_t { return 100 * i + 10 * j + k; });
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<int8_t>(),
ElementsAreArray({
100, 101, 102, 103, 110, 111, 112, 113, // Row 1
0, 1, 2, 3, 10, 11, 12, 13, // Row 0
200, 201, 202, 203, 210, 211, 212, 213, // Row 2
}));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple2DTestInt8) {
PerAxisHybridEmbeddingLookupOpModel m(
{3}, {3, 8}, {0.00102, 0.0089, 0.016772}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple3DTestInt8) {
PerAxisHybridEmbeddingLookupOpModel m(
{3}, {3, 2, 4}, {0.00102, 0.0089, 0.016772}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt8) {
PerAxisHybridEmbeddingLookupOpModel m(
{3}, {3, 2, 2, 2}, {0.00102, 0.0089, 0.016772}, TensorType_INT8);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt8Float16) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2},
{0.00102, 0.0089, 0.016772},
TensorType_INT8, TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
1.00, -1.01, 1.02, 1.03, 1.10, 1.11, 1.12, 1.13, // Row 1
0.00, 0.01, 0.02, 0.03, 0.10, 0.11, 0.12, 0.13, // Row 0
2.00, 2.01, 2.02, 2.03, 2.10, 2.11, 2.12, 2.13, // Row 2
},
kFp16TestTolerance)));
}
TEST(PerBlockHybridEmbeddingLookupHybridOpTest, PerBlockSimple2DTestInt4) {
PerBlockHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3},
/*weight_shape=*/{3, 8},
/*type=*/TensorType_INT4,
/*blocksize=*/4,
/*scales=*/{0.001, 0.001, 0.02, 0.02, 0.3, 0.3});
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kTestTolerance)));
}
TEST(PerBlockHybridEmbeddingLookupHybridOpTest, PerBlockSimple2DTestInt2) {
PerBlockHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3},
/*weight_shape=*/{3, 16},
/*weights_type=*/TensorType_INT2,
/*blocksize=*/8,
/*scales=*/{1.0, 2.0, 0.5, 0.25, 4.0, 0.5});
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, // Row 0
0.0, -2.0, 0.0, 2.0, 2.0, -2.0, 0.0, 2.0,
-0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, // Row 1
0.25, 0.0, -0.25, 0.25, -0.25, -0.25, 0.0, 0.25,
4.0, -4.0, 0.0, 4.0, -4.0, -4.0, 0.0, 4.0, // Row 2
0.5, -0.5, 0.0, 0.5, -0.5, -0.5, 0.0, 0.5,
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
-0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, // Row 1
0.25, 0.0, -0.25, 0.25, -0.25, -0.25, 0.0, 0.25,
0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, // Row 0
0.0, -2.0, 0.0, 2.0, 2.0, -2.0, 0.0, 2.0,
4.0, -4.0, 0.0, 4.0, -4.0, -4.0, 0.0, 4.0, // Row 2
0.5, -0.5, 0.0, 0.5, -0.5, -0.5, 0.0, 0.5,
},
kTestTolerance)));
}
TEST(PerBlockHybridEmbeddingLookupHybridOpTest,
PerBlockSimple2DTestInt4Float16) {
PerBlockHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3},
/*weight_shape=*/{3, 8},
/*weights_type=*/TensorType_INT4,
/*blocksize=*/4,
/*scales=*/{0.001, 0.001, 0.02, 0.02, 0.3, 0.3},
/*output_type=*/TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kFp16TestTolerance)));
}
TEST(PerBlockHybridEmbeddingLookupHybridOpTest,
PerBlockSimple2DTestInt2Float16) {
PerBlockHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3},
/*weight_shape=*/{3, 16},
/*weights_type=*/TensorType_INT2,
/*blocksize=*/8,
/*scales=*/{1.0, 2.0, 0.5, 0.25, 4.0, 0.5},
/*output_type=*/TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, // Row 0
0.0, -2.0, 0.0, 2.0, 2.0, -2.0, 0.0, 2.0,
-0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, // Row 1
0.25, 0.0, -0.25, 0.25, -0.25, -0.25, 0.0, 0.25,
4.0, -4.0, 0.0, 4.0, -4.0, -4.0, 0.0, 4.0, // Row 2
0.5, -0.5, 0.0, 0.5, -0.5, -0.5, 0.0, 0.5,
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
-0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, // Row 1
0.25, 0.0, -0.25, 0.25, -0.25, -0.25, 0.0, 0.25,
0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, // Row 0
0.0, -2.0, 0.0, 2.0, 2.0, -2.0, 0.0, 2.0,
4.0, -4.0, 0.0, 4.0, -4.0, -4.0, 0.0, 4.0, // Row 2
0.5, -0.5, 0.0, 0.5, -0.5, -0.5, 0.0, 0.5,
},
kFp16TestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple2DTestInt4) {
PerAxisHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3}, /*weight_shape=*/{3, 8},
/*per_channel_quantization_scales=*/{0.001, 0.02, 0.3},
/*type=*/TensorType_INT4);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple3DTestInt4) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 4}, {0.001, 0.02, 0.3},
TensorType_INT4);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt4) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, {0.001, 0.02, 0.3},
TensorType_INT4);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<float>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt4Float16) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 2}, {0.001, 0.02, 0.3},
TensorType_INT4, TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(
m.GetOutput<half>(),
ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02, 0.04, 0.06, 0.08, -0.04, -0.08, -0.06, // Row 1
0.00, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001, // Row 0
0.3, 0.6, 0.9, 1.2, 1.5, -0.3, -0.6, -0.9, // Row 2
},
kFp16TestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple2DTestInt2) {
PerAxisHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3}, /*weight_shape=*/{3, 4},
/*per_channel_quantization_scales=*/{0.001, 0.02, 0.3},
/*type=*/TensorType_INT2);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.3,
-0.6,
0.0,
-0.3, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.3,
-0.6,
0.0,
-0.3, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple3DTestInt2) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2}, {0.001, 0.02, 0.3},
TensorType_INT2);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.3,
-0.6,
0.0,
-0.3, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.3,
-0.6,
0.0,
-0.3, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt2) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 1}, {0.001, 0.02, 0.3},
TensorType_INT2);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.3,
-0.6,
0.0,
-0.3, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.3,
-0.6,
0.0,
-0.3, // Row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt2Float16) {
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 2, 1}, {0.001, 0.02, 0.3},
TensorType_INT2, TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.3,
-0.6,
0.0,
-0.3, // Row 2
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(), ElementsAreArray(ArrayFloatNear(
{
0.02,
-0.02,
0.00,
-0.04, // Row 1
0.00,
-0.001,
-0.002,
0.001, // Row 0
0.3,
-0.6,
0.0,
-0.3, // Row 2
},
kFp16TestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple2DTestInt2Rem) {
// Since our packing algorithm assumes the rem value is 0, this test ensures
// that the column size is a multiple of 4 and we have 0 paddings.
PerAxisHybridEmbeddingLookupOpModel m(
/*index_shape=*/{3}, /*weight_shape=*/{3, 4},
/*per_channel_quantization_scales=*/{0.001, 0.02, 0.3},
/*type=*/TensorType_INT2);
m.SetInput({1, 0, 2});
// 0.001 * {0b00, 0b11, 0b10, padding 0b00} -> 0.001 * = 0b00101100
// 0.02 * {0b01, 0b11, 0b00, padding 0b00} -> 0.001 * = 0b00001101
// 0.3 * {0b01, 0b10, 0b00, padding 0b00} -> 0.001 * = 0b00001001
m.SetSignedWeight({
0.00,
-0.001,
-0.002, // Row 0
0.00, // Padding for row 0 serialization.
0.02,
-0.02,
0.00, // Row 1
0.00, // Padding for row 1 serialization.
0.3,
-0.6,
-0.3, // Row 2
0.00, // Padding for row 2 serialization.
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02,
-0.02,
0.00, // Row 1
0.00, // Padding for row 1.
0.00,
-0.001,
-0.002, // Row 0
0.0, // Padding for row 0.
0.3,
-0.6,
-0.3, // Row 2
0.0, // Padding for row 2.
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple3DTestInt2Rem) {
// We still need padding due to packing algorithm.
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 4}, {0.001, 0.02, 0.3},
TensorType_INT2);
m.SetInput({1, 0, 2});
// Each row has 2*3 = 6 elements with 2 * 1 zero paddings.
m.SetSignedWeight({
0.00, -0.001,
-0.002, // Row 00
0.00, // Padding for row 00 serialization.
0.001, -0.002,
0.001, // Row 01
0.00, // Padding for row 01 serialization.
0.02, -0.02,
0.00, // Row 10
0.00, // Padding for row 10 serialization.
-0.04, 0.00,
-0.04, // Row 11
0.00, // Padding for row 11 serialization.
0.3, -0.6,
0.0, // Row 20
0.00, // Padding for row 20 serialization.
-0.3, 0.0,
-0.3, // Row 21
0.00, // Padding for row 21 serialization.
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02, -0.02,
0.00, // Row 10
0.00, // Padding for row 10
-0.04, 0.00,
-0.04, // Row 11
0.00, // Padding for row 11
0.00, -0.001,
-0.002, // Row 00
0.00, // Padding for row 00
0.001, -0.002,
0.001, // Row 01
0.00, // Padding for row 01
0.3, -0.6,
0.0, // Row 20
0.00, // Padding for row 20
-0.3, 0.0,
-0.3, // Row 21
0.00, // Padding for row 2
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest, PerAxisSimple4DTestInt2Rem) {
// We still need padding due to packing algorithm.
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 4, 1}, {0.001, 0.02, 0.3},
TensorType_INT2);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, // Row 000
-0.001, // Row 001
-0.002, // Row 002
0.00, // Padding for row 00
0.001, // Row 010
-0.002, // Row 011
0.001, // Row 012
0.00, // Padding for row 01
0.02, // Row 100
-0.02, // Row 101
0.00, // Row 102
0.00, // Padding for row 10
-0.04, // Row 110
0.00, // Row 111
-0.04, // Row 112
0.00, // Padding for row 11
0.3, // Row 200
-0.6, // Row 201
0.0, // Row 202
0.00, // Padding for row 20
-0.3, // Row 210
0.0, // Row 211
-0.3, // Row 212
0.0, // Padding for row 21
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray(ArrayFloatNear(
{
0.02, // Row 100
-0.02, // Row 101
0.00, // Row 102
0.00, // Padding for row 10
-0.04, // Row 110
0.00, // Row 111
-0.04, // Row 112
0.00, // Padding for row 11
0.00, // Row 000
-0.001, // Row 001
-0.002, // Row 002
0.00, // Padding for row 00
0.001, // Row 010
-0.002, // Row 011
0.001, // Row 012
0.00, // Padding for row 01
0.3, // Row 200
-0.6, // Row 201
0.0, // Row 202
0.00, // Padding for row 20
-0.3, // Row 210
0.0, // Row 211
-0.3, // Row 212
0.0, // Padding for row 21
},
kTestTolerance)));
}
TEST(PerAxisHybridEmbeddingLookupHybridOpTest,
PerAxisSimple4DTestInt2RemFloat16) {
// We still need padding due to packing algorithm.
PerAxisHybridEmbeddingLookupOpModel m({3}, {3, 2, 4, 1}, {0.001, 0.02, 0.3},
TensorType_INT2, TensorType_FLOAT16);
m.SetInput({1, 0, 2});
m.SetSignedWeight({
0.00, // Row 000
-0.001, // Row 001
-0.002, // Row 002
0.00, // Padding for row 00
0.001, // Row 010
-0.002, // Row 011
0.001, // Row 012
0.00, // Padding for row 01
0.02, // Row 100
-0.02, // Row 101
0.00, // Row 102
0.00, // Padding for row 10
-0.04, // Row 110
0.00, // Row 111
-0.04, // Row 112
0.00, // Padding for row 11
0.3, // Row 200
-0.6, // Row 201
0.0, // Row 202
0.00, // Padding for row 20
-0.3, // Row 210
0.0, // Row 211
-0.3, // Row 212
0.0, // Padding for row 21
});
ASSERT_EQ(m.Invoke(), kTfLiteOk);
EXPECT_THAT(m.GetOutput<half>(), ElementsAreArray(ArrayFloatNear(
{
0.02, // Row 100
-0.02, // Row 101
0.00, // Row 102
0.00, // Padding for row 10
-0.04, // Row 110
0.00, // Row 111
-0.04, // Row 112
0.00, // Padding for row 11
0.00, // Row 000
-0.001, // Row 001
-0.002, // Row 002
0.00, // Padding for row 00
0.001, // Row 010
-0.002, // Row 011
0.001, // Row 012
0.00, // Padding for row 01
0.3, // Row 200
-0.6, // Row 201
0.0, // Row 202
0.00, // Padding for row 20
-0.3, // Row 210
0.0, // Row 211
-0.3, // Row 212
0.0, // Padding for row 21
},
kFp16TestTolerance)));
}
} // namespace
} // namespace tflite