chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_binary",
"tf_cc_test",
)
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:public",
],
licenses = ["notice"],
)
cc_library(
name = "util",
hdrs = ["util.h"],
deps = [
":input_generator",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/testing:split",
"//tensorflow/lite/testing:tflite_driver",
] + select({
"//conditions:default": [
"//tensorflow/core:framework_internal",
"//tensorflow/core:lib",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
],
}),
)
tf_cc_test(
name = "util_test",
size = "small",
srcs = ["util_test.cc"],
data = [
":testdata/test_input.csv",
"//tensorflow/lite:testdata/add.bin",
],
deps = [
":util",
"//tensorflow/lite/testing:tflite_driver",
"@com_google_googletest//:gtest_main",
],
)
tf_cc_binary(
name = "tflite_kernel_runner",
srcs = ["tflite_kernel_runner.cc"],
deps = [
":util",
],
)
tf_cc_binary(
name = "generate_diff_report",
srcs = ["generate_diff_report.cc"],
deps = [
":diff_analyzer",
"//tensorflow/core:framework_internal",
],
)
cc_library(
name = "input_generator",
srcs = ["input_generator.cc"],
hdrs = ["input_generator.h"],
deps = [
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
"//tensorflow/lite/core:framework",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/kernels:builtin_ops",
"//tensorflow/lite/testing:join",
"//tensorflow/lite/testing:split",
],
)
cc_test(
name = "input_generator_test",
size = "small",
srcs = ["input_generator_test.cc"],
data = [
":testdata/test_input.csv",
"//tensorflow/lite:testdata/multi_add.bin",
],
deps = [
":input_generator",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "diff_analyzer",
srcs = ["diff_analyzer.cc"],
hdrs = ["diff_analyzer.h"],
deps = [
"//tensorflow/lite:string",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/testing:split",
],
)
tf_cc_test(
name = "diff_analyzer_test",
size = "small",
srcs = ["diff_analyzer_test.cc"],
data = [
":testdata/test_input.csv",
],
deps = [
":diff_analyzer",
"//tensorflow/core:lib",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,133 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <fstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/testing/split.h"
namespace tflite {
namespace testing {
namespace {
float CalculateNormalizedMaxDiff(const std::vector<float>& base,
const std::vector<float>& test) {
float diff = 0;
// For numerical stability in case the tensor is all 0.
float base_max = 1e-6;
for (int i = 0; i < base.size(); i++) {
diff = std::max(diff, std::abs(base[i] - test[i]));
base_max = std::max(base_max, base[i]);
}
return diff / base_max;
}
float CalculateNormalizedL2Norm(const std::vector<float>& base,
const std::vector<float>& test) {
float l2_error = 0;
// For numerical stability in case the tensor is all 0.
float base_max = 1e-6;
for (int i = 0; i < base.size(); i++) {
float diff = base[i] - test[i];
l2_error += diff * diff;
base_max = std::max(base_max, base[i]);
}
l2_error /= base.size();
return std::sqrt(l2_error) / base_max;
}
TfLiteStatus Populate(const string& filename,
std::unordered_map<string, std::vector<float>>* tensors) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ifstream file(filename);
string content;
while (std::getline(file, content, '\n')) {
auto parts = Split<string>(content, ":");
if (parts.size() != 2) {
fprintf(stderr, "Expected <name>:<value>, got %s", content.c_str());
return kTfLiteError;
}
tensors->insert(std::make_pair(parts[0], Split<float>(parts[1], ",")));
}
file.close();
return kTfLiteOk;
}
} // namespace
TfLiteStatus DiffAnalyzer::ReadFiles(const string& base, const string& test) {
TF_LITE_ENSURE_STATUS(Populate(base, &base_tensors_));
TF_LITE_ENSURE_STATUS(Populate(test, &test_tensors_));
if (base_tensors_.size() != test_tensors_.size()) {
fprintf(stderr, "Golden and test tensor dimensions don't match.");
return kTfLiteError;
}
return kTfLiteOk;
}
TfLiteStatus DiffAnalyzer::WriteReport(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty output file name.");
return kTfLiteError;
}
std::ofstream output_file;
output_file.open(filename, std::fstream::out | std::fstream::trunc);
if (!output_file) {
fprintf(stderr, "Failed to open output file %s.", filename.c_str());
return kTfLiteError;
}
output_file << "Normalized L2 Error"
<< ","
<< "Normalized Max Diff"
<< "\n";
for (const auto& item : base_tensors_) {
const auto& name = item.first;
if (!test_tensors_.count(name)) {
fprintf(stderr, "Missing tensor %s in test tensors.", name.c_str());
continue;
}
float l2_error =
CalculateNormalizedL2Norm(base_tensors_[name], test_tensors_[name]);
float max_diff =
CalculateNormalizedMaxDiff(base_tensors_[name], test_tensors_[name]);
output_file << name << ":" << l2_error << "," << max_diff << "\n";
}
output_file.close();
return kTfLiteOk;
}
} // namespace testing
} // namespace tflite
@@ -0,0 +1,49 @@
/* 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 TENSORFLOW_LITE_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
#include <string>
#include <unordered_map>
#include <vector>
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Reads the baseline and test files with output tensor values, and calculates
// the diff metrics.
class DiffAnalyzer {
public:
DiffAnalyzer() = default;
// Reads base and test tensor values from files.
// Each file have lines in <name>:<values> format, where name is the signature
// output name and value as comma separated value string.
TfLiteStatus ReadFiles(const string& base, const string& test);
// Writes diff report in <name>:<L2 Error>,<Max Diff> format.
TfLiteStatus WriteReport(const string& filename);
private:
// Mappings from signature output names to its values.
std::unordered_map<string, std::vector<float>> base_tensors_;
std::unordered_map<string, std::vector<float>> test_tensors_;
};
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
@@ -0,0 +1,48 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
#include <fstream>
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/core/lib/io/path.h"
namespace tflite {
namespace testing {
namespace {
TEST(DiffAnalyzerTest, ZeroDiff) {
DiffAnalyzer diff_analyzer;
string filename =
"tensorflow/lite/testing/kernel_test/testdata/test_input.csv";
ASSERT_EQ(diff_analyzer.ReadFiles(filename, filename), kTfLiteOk);
string output_file =
tensorflow::io::JoinPath(::testing::TempDir(), "diff_report.csv");
ASSERT_EQ(diff_analyzer.WriteReport(output_file), kTfLiteOk);
std::string content;
std::ifstream file(output_file);
std::getline(file, content);
std::getline(file, content);
ASSERT_EQ(content, "a:0,0");
}
} // namespace
} // namespace testing
} // namespace tflite
@@ -0,0 +1,34 @@
/* 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.
==============================================================================*/
#include <string>
#include <vector>
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
int main(int argc, char** argv) {
std::string base, test, output;
std::vector<tensorflow::Flag> flag_list = {
tensorflow::Flag("base", &base, "Path to the base serialized tensor."),
tensorflow::Flag("test", &test, "Path to the test serialized tensor."),
tensorflow::Flag("output", &output, "Path to the output file."),
};
tensorflow::Flags::Parse(&argc, argv, flag_list);
tflite::testing::DiffAnalyzer diff_analyzer;
diff_analyzer.ReadFiles(base, test);
diff_analyzer.WriteReport(output);
return 0;
}
@@ -0,0 +1,236 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <limits>
#include <random>
#include <string>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/kernels/register.h"
#include "tensorflow/lite/testing/join.h"
#include "tensorflow/lite/testing/split.h"
namespace tflite {
namespace testing {
namespace {
static constexpr char kDefaultServingSignatureDefKey[] = "serving_default";
template <typename T>
std::vector<T> GenerateRandomTensor(TfLiteIntArray* dims,
const std::function<T(int)>& random_func) {
int64_t num_elements = 1;
for (int i = 0; i < dims->size; i++) {
num_elements *= dims->data[i];
}
std::vector<T> result(num_elements);
for (int i = 0; i < num_elements; i++) {
result[i] = random_func(i);
}
return result;
}
template <typename T>
std::vector<T> GenerateUniform(TfLiteIntArray* dims, float min, float max) {
auto random_float = [](float min, float max) {
// TODO(yunluli): Change seed for each invocation if needed.
// Used rand() instead of rand_r() here to make it runnable on android.
return min + (max - min) * static_cast<float>(rand()) / RAND_MAX;
};
std::function<T(int)> random_t = [&](int) {
return static_cast<T>(random_float(min, max));
};
std::vector<T> data = GenerateRandomTensor(dims, random_t);
return data;
}
template <typename T>
std::vector<T> GenerateGaussian(TfLiteIntArray* dims, float min, float max) {
auto random_float = [](float min, float max) {
static std::default_random_engine generator;
// We generate a float number within [0, 1) following a mormal distribution
// with mean = 0.5 and stddev = 1/3, and use it to scale the final random
// number into the desired range.
static std::normal_distribution<double> distribution(0.5, 1.0 / 3);
auto rand_n = distribution(generator);
while (rand_n < 0 || rand_n >= 1) {
rand_n = distribution(generator);
}
return min + (max - min) * static_cast<float>(rand_n);
};
std::function<T(int)> random_t = [&](int) {
return static_cast<T>(random_float(min, max));
};
std::vector<T> data = GenerateRandomTensor(dims, random_t);
return data;
}
} // namespace
TfLiteStatus InputGenerator::LoadModel(const string& model_dir) {
return LoadModel(model_dir, kDefaultServingSignatureDefKey);
}
TfLiteStatus InputGenerator::LoadModel(const string& model_dir,
const string& signature) {
model_ = FlatBufferModel::BuildFromFile(model_dir.c_str());
if (!model_) {
fprintf(stderr, "Cannot load model %s", model_dir.c_str());
return kTfLiteError;
}
::tflite::ops::builtin::BuiltinOpResolver builtin_ops;
InterpreterBuilder(*model_, builtin_ops)(&interpreter_);
if (!interpreter_) {
fprintf(stderr, "Failed to build interpreter.");
return kTfLiteError;
}
signature_runner_ = interpreter_->GetSignatureRunner(signature.c_str());
if (!signature_runner_) {
fprintf(stderr, "Failed to get SignatureRunner.\n");
return kTfLiteError;
}
return kTfLiteOk;
}
TfLiteStatus InputGenerator::ReadInputsFromFile(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ifstream input_file(filename);
string input;
while (std::getline(input_file, input, '\n')) {
std::vector<string> parts = Split<string>(input, ":");
if (parts.size() != 2) {
fprintf(stderr, "Expected <name>:<value>, got %s", input.c_str());
return kTfLiteError;
}
inputs_.push_back(std::make_pair(parts[0], parts[1]));
}
input_file.close();
return kTfLiteOk;
}
TfLiteStatus InputGenerator::WriteInputsToFile(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ofstream output_file;
output_file.open(filename, std::fstream::out | std::fstream::trunc);
if (!output_file) {
fprintf(stderr, "Failed to open output file %s.", filename.c_str());
return kTfLiteError;
}
for (const auto& input : inputs_) {
output_file << input.first << ":" << input.second << "\n";
}
output_file.close();
return kTfLiteOk;
}
// TODO(yunluli): Support more tensor types when needed.
TfLiteStatus InputGenerator::GenerateInput(const string& distribution) {
auto input_tensor_names = signature_runner_->input_names();
for (const char* name : input_tensor_names) {
auto* tensor = signature_runner_->input_tensor(name);
if (distribution == "UNIFORM") {
switch (tensor->type) {
case kTfLiteInt8: {
auto data = GenerateUniform<int8_t>(
tensor->dims, std::numeric_limits<int8_t>::min(),
std::numeric_limits<int8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteUInt8: {
auto data = GenerateUniform<uint8_t>(
tensor->dims, std::numeric_limits<uint8_t>::min(),
std::numeric_limits<uint8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteFloat32: {
auto data = GenerateUniform<float>(tensor->dims, -1, 1);
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
default:
fprintf(stderr, "Unsupported input tensor type %s.",
TfLiteTypeGetName(tensor->type));
break;
}
} else if (distribution == "GAUSSIAN") {
switch (tensor->type) {
case kTfLiteInt8: {
auto data = GenerateGaussian<int8_t>(
tensor->dims, std::numeric_limits<int8_t>::min(),
std::numeric_limits<int8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteUInt8: {
auto data = GenerateGaussian<uint8_t>(
tensor->dims, std::numeric_limits<uint8_t>::min(),
std::numeric_limits<uint8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteFloat32: {
auto data = GenerateGaussian<float>(tensor->dims, -1, 1);
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
default:
fprintf(stderr, "Unsupported input tensor type %s.",
TfLiteTypeGetName(tensor->type));
break;
}
} else {
fprintf(stderr, "Unsupported distribution %s.", distribution.c_str());
return kTfLiteError;
}
}
return kTfLiteOk;
}
} // namespace testing
} // namespace tflite
@@ -0,0 +1,58 @@
/* 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 TENSORFLOW_LITE_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/interpreter.h"
#include "tensorflow/lite/core/model.h"
#include "tensorflow/lite/signature_runner.h"
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Generate random input, or read input from a file for kernel diff test.
// Needs to load the tflite graph to get information like tensor shape and
// data type.
class InputGenerator {
public:
InputGenerator() = default;
TfLiteStatus LoadModel(const string& model_dir);
TfLiteStatus LoadModel(const string& model_dir, const string& signature);
TfLiteStatus ReadInputsFromFile(const string& filename);
TfLiteStatus GenerateInput(const string& distribution);
std::vector<std::pair<string, string>> GetInputs() { return inputs_; }
TfLiteStatus WriteInputsToFile(const string& filename);
private:
std::unique_ptr<FlatBufferModel> model_;
std::unique_ptr<Interpreter> interpreter_;
// Not owned.
SignatureRunner* signature_runner_ = nullptr;
// Mapping from input names to csv string values.
std::vector<std::pair<string, string>> inputs_;
};
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
@@ -0,0 +1,83 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include <fstream>
#include <string>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
namespace tflite {
namespace testing {
namespace {
TEST(InputGeneratorTest, LoadModel) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
}
TEST(InputGeneratorTest, ReadWriteSimpleFile) {
InputGenerator input_generator;
ASSERT_EQ(
input_generator.ReadInputsFromFile("tensorflow/lite/testing/"
"kernel_test/testdata/test_input.csv"),
kTfLiteOk);
std::string content = "1";
for (int i = 0; i < 1 * 8 * 8 * 3 - 1; i++) {
content.append(",1");
}
std::vector<std::pair<string, string>> inputs = {{"a", content}};
ASSERT_EQ(input_generator.GetInputs(), inputs);
auto output_filename = ::testing::TempDir() + "/out.csv";
ASSERT_EQ(input_generator.WriteInputsToFile(output_filename), kTfLiteOk);
std::ifstream in(output_filename);
std::string out;
std::getline(in, out, '\n');
std::string expected_out = "a:";
expected_out.append(content);
ASSERT_EQ(out, expected_out);
}
TEST(InputGeneratorTest, GenerateUniformInput) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
input_generator.GenerateInput("UNIFORM");
auto inputs = input_generator.GetInputs();
ASSERT_EQ(inputs.size(), 4);
}
TEST(InputGeneratorTest, GenerateGaussianInput) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
input_generator.GenerateInput("GAUSSIAN");
auto inputs = input_generator.GetInputs();
ASSERT_EQ(inputs.size(), 4);
}
} // namespace
} // namespace testing
} // namespace tflite
@@ -0,0 +1 @@
a:1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1 a:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
@@ -0,0 +1,37 @@
/* 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.
==============================================================================*/
#include <memory>
#include "tensorflow/lite/testing/kernel_test/util.h"
int main(int argc, char** argv) {
tflite::testing::kernel_test::TestOptions options =
tflite::testing::kernel_test::ParseTfliteKernelTestFlags(&argc, argv);
const bool run_reference_kernel = options.kernel_type == "REFERENCE";
const tflite::testing::TfLiteDriver::DelegateType delegate_type =
options.kernel_type == "NNAPI"
? tflite::testing::TfLiteDriver::DelegateType::kNnapi
: tflite::testing::TfLiteDriver::DelegateType::kNone;
auto runner = std::make_unique<tflite::testing::TfLiteDriver>(
delegate_type, run_reference_kernel);
if (tflite::testing::kernel_test::RunKernelTest(options, runner.get()) ==
kTfLiteOk) {
return 0;
}
return -1;
}
+113
View File
@@ -0,0 +1,113 @@
/* 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 TENSORFLOW_LITE_TESTING_KERNEL_TEST_UTIL_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_UTIL_H_
#include <fstream>
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include "tensorflow/lite/testing/split.h"
#include "tensorflow/lite/testing/tflite_driver.h"
namespace tflite {
namespace testing {
namespace kernel_test {
struct TestOptions {
// Path of tensorflow lite model.
string tflite_model;
// Path of the input file. If empty, generate at runtime.
string read_input_from_file;
// Path to dump the input file.
string dump_input_to_file;
// Path to dump the output.
string dump_output_to_file;
// Input distribution.
string input_distribution;
// Kernel type.
string kernel_type;
};
inline TestOptions ParseTfliteKernelTestFlags(int* argc, char** argv) {
TestOptions options;
std::vector<tensorflow::Flag> flags = {
tensorflow::Flag("tflite_model", &options.tflite_model,
"Path of tensorflow lite model."),
tensorflow::Flag("read_input_from_file", &options.read_input_from_file,
"File to read input data from. If empty, generates "
"input at runtime."),
tensorflow::Flag("dump_input_to_file", &options.dump_input_to_file,
"File to dump randomly generated input."),
tensorflow::Flag("dump_output_to_file", &options.dump_output_to_file,
"File to dump output."),
tensorflow::Flag("input_distribution", &options.input_distribution,
"Input distribution. Default: Gaussian."),
tensorflow::Flag("kernel_type", &options.kernel_type, "Kernel type."),
};
tensorflow::Flags::Parse(argc, argv, flags);
return options;
}
inline TfLiteStatus RunKernelTest(const kernel_test::TestOptions& options,
TestRunner* runner) {
InputGenerator input_generator;
if (options.read_input_from_file.empty()) {
TF_LITE_ENSURE_STATUS(input_generator.LoadModel(options.tflite_model));
TF_LITE_ENSURE_STATUS(
input_generator.GenerateInput(options.input_distribution));
} else {
TF_LITE_ENSURE_STATUS(
input_generator.ReadInputsFromFile(options.read_input_from_file));
}
runner->LoadModel(options.tflite_model);
runner->AllocateTensors();
if (!runner->IsValid()) return kTfLiteError;
auto inputs = input_generator.GetInputs();
runner->Invoke(inputs);
if (!options.dump_input_to_file.empty()) {
TF_LITE_ENSURE_STATUS(
input_generator.WriteInputsToFile(options.dump_input_to_file));
}
if (!options.dump_output_to_file.empty()) {
std::ofstream output_file;
output_file.open(options.dump_output_to_file,
std::fstream::out | std::fstream::trunc);
if (!output_file) {
return kTfLiteError;
}
for (const auto& name : runner->GetOutputNames()) {
output_file << name << ":" << runner->ReadOutput(name) << "\n";
}
output_file.close();
}
return kTfLiteOk;
}
} // namespace kernel_test
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_UTIL_H_
@@ -0,0 +1,52 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/util.h"
#include <fstream>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/lite/testing/tflite_driver.h"
namespace tflite {
namespace testing {
namespace kernel_test {
namespace {
TEST(UtilTest, SimpleE2ETest) {
TestOptions options;
options.tflite_model = "tensorflow/lite/testdata/add.bin";
options.read_input_from_file =
"tensorflow/lite/testing/kernel_test/testdata/test_input.csv";
options.dump_output_to_file = ::testing::TempDir() + "/test_out.csv";
options.kernel_type = "REFERENCE";
std::unique_ptr<TestRunner> runner(new TfLiteDriver(
TfLiteDriver::DelegateType::kNone, /*reference_kernel=*/true));
RunKernelTest(options, runner.get());
std::string expected = "x:3";
for (int i = 0; i < 1 * 8 * 8 * 3 - 1; i++) {
expected.append(",3");
}
std::string content;
std::ifstream file(options.dump_output_to_file);
std::getline(file, content);
EXPECT_EQ(content, expected);
}
} // namespace
} // namespace kernel_test
} // namespace testing
} // namespace tflite