summaryrefslogtreecommitdiff
path: root/libs/support
diff options
context:
space:
mode:
Diffstat (limited to 'libs/support')
-rw-r--r--libs/support/CMakeLists.txt2
-rw-r--r--libs/support/nnapi/CMakeLists.txt6
-rw-r--r--libs/support/nnapi/src/feature/Utils.cpp43
-rw-r--r--libs/support/tflite/CMakeLists.txt10
-rw-r--r--libs/support/tflite/src/Diff.cpp262
-rw-r--r--libs/support/tflite/src/FeatureView.cpp76
-rw-r--r--libs/support/tflite/src/TensorView.cpp69
-rw-r--r--libs/support/tflite/src/TensorView.test.cpp36
-rw-r--r--libs/support/tflite/src/interp/FlatBufferBuilder.cpp46
-rw-r--r--libs/support/tflite/src/interp/FunctionBuilder.cpp40
10 files changed, 590 insertions, 0 deletions
diff --git a/libs/support/CMakeLists.txt b/libs/support/CMakeLists.txt
new file mode 100644
index 000000000..c91677266
--- /dev/null
+++ b/libs/support/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(tflite)
+add_subdirectory(nnapi)
diff --git a/libs/support/nnapi/CMakeLists.txt b/libs/support/nnapi/CMakeLists.txt
new file mode 100644
index 000000000..cd1f365cf
--- /dev/null
+++ b/libs/support/nnapi/CMakeLists.txt
@@ -0,0 +1,6 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(nnfw_support_nnapi ${SOURCES})
+set_property(TARGET nnfw_support_nnapi PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_include_directories(nnfw_support_nnapi PUBLIC ${CMAKE_SOURCE_DIR}/include)
+target_link_libraries(nnfw_support_nnapi nnfw_util)
diff --git a/libs/support/nnapi/src/feature/Utils.cpp b/libs/support/nnapi/src/feature/Utils.cpp
new file mode 100644
index 000000000..62939ff4a
--- /dev/null
+++ b/libs/support/nnapi/src/feature/Utils.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/nnapi/feature/Utils.h"
+
+namespace nnfw
+{
+namespace support
+{
+namespace nnapi
+{
+namespace feature
+{
+
+uint32_t indexOf(const nnfw::util::feature::Shape &shape, uint32_t ch, uint32_t row, uint32_t col)
+{
+ uint32_t res = 0;
+
+ // NNAPI assumes that NHWC ordering for feature map
+ res += row * shape.W * shape.C;
+ res += col * shape.C;
+ res += ch;
+
+ return res;
+}
+
+} // namespace feature
+} // namespace nnapi
+} // namespace support
+} // namespace nnfw
diff --git a/libs/support/tflite/CMakeLists.txt b/libs/support/tflite/CMakeLists.txt
new file mode 100644
index 000000000..cccc7de3d
--- /dev/null
+++ b/libs/support/tflite/CMakeLists.txt
@@ -0,0 +1,10 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(nnfw_support_tflite ${SOURCES})
+target_include_directories(nnfw_support_tflite PUBLIC ${CMAKE_SOURCE_DIR}/include)
+target_link_libraries(nnfw_support_tflite nnfw_util tensorflow-lite ${LIB_PTHREAD} dl)
+
+add_executable(nnfw_support_tflite_test_TensorView src/TensorView.test.cpp)
+target_link_libraries(nnfw_support_tflite_test_TensorView nnfw_support_tflite)
diff --git a/libs/support/tflite/src/Diff.cpp b/libs/support/tflite/src/Diff.cpp
new file mode 100644
index 000000000..f382df2d6
--- /dev/null
+++ b/libs/support/tflite/src/Diff.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/Diff.h"
+
+#include "util/fp32.h"
+
+#include "util/tensor/IndexIterator.h"
+#include "util/tensor/IndexFormatter.h"
+#include "util/tensor/Zipper.h"
+
+#include <iostream>
+
+class DiffSummary : public TfLiteTensorComparator::Observer
+{
+public:
+ DiffSummary()
+ : max_abs_diff_index(0), max_abs_diff_value{0.0f},
+ max_rel_diff_index(0), max_rel_diff_value{0.0f}
+ {
+ // DO NOTHING
+ }
+public:
+ void notify(const nnfw::util::tensor::Index &index, float expected, float obtained) override;
+
+public:
+ nnfw::util::tensor::Index max_abs_diff_index;
+ float max_abs_diff_expected;
+ float max_abs_diff_obtained;
+ float max_abs_diff_value;
+
+ nnfw::util::tensor::Index max_rel_diff_index;
+ float max_rel_diff_expected;
+ float max_rel_diff_obtained;
+ float max_rel_diff_value;
+};
+
+void DiffSummary::notify(const nnfw::util::tensor::Index &index, float expected, float obtained)
+{
+ const auto abs_diff_value = std::fabs(expected - obtained);
+
+ if (max_abs_diff_value < abs_diff_value)
+ {
+ max_abs_diff_index = index;
+ max_abs_diff_value = abs_diff_value;
+ max_abs_diff_expected = expected;
+ max_abs_diff_obtained = obtained;
+ }
+
+ const auto rel_diff_value = nnfw::util::fp32::relative_diff(expected, obtained);
+
+ if (max_rel_diff_value < rel_diff_value)
+ {
+ max_rel_diff_index = index;
+ max_rel_diff_value = rel_diff_value;
+ max_rel_diff_expected = expected;
+ max_rel_diff_obtained = obtained;
+ }
+}
+
+std::vector<TfLiteTensorDiff>
+TfLiteTensorComparator::compare(const nnfw::support::tflite::TensorView<float> &expected,
+ const nnfw::support::tflite::TensorView<float> &obtained,
+ Observer *observer) const
+{
+ std::vector<TfLiteTensorDiff> res;
+
+ assert(expected.shape() == obtained.shape());
+
+ nnfw::util::tensor::zip(expected.shape(), expected, obtained) <<
+ [&] (const nnfw::util::tensor::Index &index, float expected_value, float obtained_value)
+ {
+ const auto relative_diff = nnfw::util::fp32::relative_diff(expected_value, obtained_value);
+
+ if (!_compare_fn(expected_value, obtained_value))
+ {
+ TfLiteTensorDiff diff(index);
+
+ diff.expected = expected_value;
+ diff.obtained = obtained_value;
+
+ res.emplace_back(diff);
+ }
+
+ // Update max_diff_index, if necessary
+ if (observer != nullptr)
+ {
+ observer->notify(index, expected_value, obtained_value);
+ }
+ };
+
+ return res;
+}
+
+bool TfLiteInterpMatchApp::run(::tflite::Interpreter &interp, ::tflite::Interpreter &nnapi) const
+{
+ assert(interp.outputs() == nnapi.outputs());
+
+ for (const auto &id : interp.outputs())
+ {
+ const auto expected = nnfw::support::tflite::TensorView<float>::make(interp, id);
+ const auto obtained = nnfw::support::tflite::TensorView<float>::make(nnapi, id);
+
+ DiffSummary summary;
+
+ auto diffs = _comparator.compare(expected, obtained, &summary);
+
+ if (diffs.size() == 0)
+ {
+ std::cout << " Tensor #" << id << ": MATCHED" << std::endl;
+ }
+ else
+ {
+ std::cout << " Tensor #" << id << ": UNMATCHED" << std::endl;
+ std::cout << " " << diffs.size() << " diffs are detected" << std::endl;
+ }
+
+ // Print out max_diff
+ if (summary.max_abs_diff_value > 0)
+ {
+ std::cout << " Max absolute diff at [" << nnfw::util::tensor::IndexFormatter(summary.max_abs_diff_index) << "]" << std::endl;
+ std::cout << " expected: " << summary.max_abs_diff_expected << std::endl;
+ std::cout << " obtained: " << summary.max_abs_diff_obtained << std::endl;
+ std::cout << " absolute diff: " << summary.max_abs_diff_value << std::endl;
+ }
+
+ if (summary.max_rel_diff_value > 0)
+ {
+ const auto tolerance_level = summary.max_rel_diff_value / FLT_EPSILON;
+
+ std::cout << " Max relative diff at [" << nnfw::util::tensor::IndexFormatter(summary.max_rel_diff_index) << "]" << std::endl;
+ std::cout << " expected: " << summary.max_rel_diff_expected << std::endl;
+ std::cout << " obtained: " << summary.max_rel_diff_obtained << std::endl;
+ std::cout << " relative diff: " << summary.max_rel_diff_value << std::endl;
+ std::cout << " (tolerance level = " << tolerance_level << ")" << std::endl;
+ }
+
+ if (diffs.size() > 0)
+ {
+ if (_verbose != 0)
+ {
+ std::cout << " ---- Details ---" << std::endl;
+ for (const auto &diff : diffs)
+ {
+ const auto absolute_diff = std::fabs(diff.expected - diff.obtained);
+ const auto relative_diff = nnfw::util::fp32::relative_diff(diff.expected, diff.obtained);
+ const auto tolerance_level = relative_diff / FLT_EPSILON;
+
+ std::cout << " Diff at [" << nnfw::util::tensor::IndexFormatter(diff.index) << "]" << std::endl;
+ std::cout << " expected: " << diff.expected << std::endl;
+ std::cout << " obtained: " << diff.obtained << std::endl;
+ std::cout << " absolute diff: " << absolute_diff << std::endl;
+ std::cout << " relative diff: " << relative_diff << std::endl;
+ std::cout << " (tolerance level = " << tolerance_level << ")" << std::endl;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#include "util/tensor/Object.h"
+
+//
+// Random Test Runner
+//
+int RandomTestRunner::run(const nnfw::support::tflite::interp::Builder &builder)
+{
+ auto pure = builder.build();
+ auto nnapi = builder.build();
+
+ pure->UseNNAPI(false);
+ nnapi->UseNNAPI(true);
+
+ // Allocate Tensors
+ pure->AllocateTensors();
+ nnapi->AllocateTensors();
+
+ assert(pure->inputs() == nnapi->inputs());
+
+ // Fill IFM with random numbers
+ auto ifm_gen = [this] (const nnfw::util::tensor::Shape &, const nnfw::util::tensor::Index &)
+ {
+ // TODO Allow users to set min/max and distribution
+ std::normal_distribution<float> dist(0.0f, 2.0f);
+ return dist(_rand);
+ };
+
+ for (const auto id : pure->inputs())
+ {
+ auto pure_view = nnfw::support::tflite::TensorView<float>::make(*pure, id);
+ auto nnapi_view = nnfw::support::tflite::TensorView<float>::make(*nnapi, id);
+
+ assert(pure_view.shape() == nnapi_view.shape());
+
+ const nnfw::util::tensor::Object<float> data(pure_view.shape(), ifm_gen);
+
+ assert(pure_view.shape() == data.shape());
+
+ nnfw::util::tensor::iterate(pure_view.shape()) << [&] (const nnfw::util::tensor::Index &ind)
+ {
+ const auto value = data.at(ind);
+
+ pure_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ }
+
+ std::cout << "[NNAPI TEST] Run T/F Lite Interpreter without NNAPI" << std::endl;
+ pure->Invoke();
+
+ std::cout << "[NNAPI TEST] Run T/F Lite Interpreter with NNAPI" << std::endl;
+ nnapi->Invoke();
+
+ // Compare OFM
+ std::cout << "[NNAPI TEST] Compare the result" << std::endl;
+
+ const auto tolerance = _param.tolerance;
+
+ auto equals = [tolerance] (float lhs, float rhs)
+ {
+ // NOTE Hybrid approach
+ // TODO Allow users to set tolerance for absolute_epsilon_equal
+ if (nnfw::util::fp32::absolute_epsilon_equal(lhs, rhs))
+ {
+ return true;
+ }
+
+ return nnfw::util::fp32::epsilon_equal(lhs, rhs, tolerance);
+ };
+
+ TfLiteTensorComparator comparator(equals);
+ TfLiteInterpMatchApp app(comparator);
+
+ app.verbose() = _param.verbose;
+
+ bool res = app.run(*pure, *nnapi);
+
+ if (!res)
+ {
+ return 255;
+ }
+
+ std::cout << "[NNAPI TEST] PASSED" << std::endl;
+ return 0;
+}
diff --git a/libs/support/tflite/src/FeatureView.cpp b/libs/support/tflite/src/FeatureView.cpp
new file mode 100644
index 000000000..50f599d2e
--- /dev/null
+++ b/libs/support/tflite/src/FeatureView.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/FeatureView.h"
+#include "support/tflite/TensorUtils.h"
+
+#include <cassert>
+
+namespace nnfw
+{
+namespace support
+{
+namespace tflite
+{
+
+nnfw::util::feature::Shape getFeatureShape(const TfLiteTensor *tensor)
+{
+ nnfw::util::feature::Shape shape;
+
+ shape.C = tensor->dims->data[3];
+ shape.H = tensor->dims->data[1];
+ shape.W = tensor->dims->data[2];
+
+ return shape;
+}
+
+FeatureView<float>::FeatureView(::tflite::Interpreter &interp, const InputIndex &index)
+{
+ const auto tensor_index = interp.inputs().at(index.asInt());
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ assert(isFloatTensor(tensor_ptr));
+ assert(isFeatureTensor(tensor_ptr));
+
+ _shape = getFeatureShape(tensor_ptr);
+ _base = interp.typed_tensor<float>(tensor_index);
+}
+
+FeatureView<float>::FeatureView(::tflite::Interpreter &interp, const OutputIndex &index)
+{
+ const auto tensor_index = interp.outputs().at(index.asInt());
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ assert(isFloatTensor(tensor_ptr));
+ assert(isFeatureTensor(tensor_ptr));
+
+ _shape = getFeatureShape(tensor_ptr);
+ _base = interp.typed_tensor<float>(tensor_index);
+}
+
+float FeatureView<float>::at(uint32_t ch, uint32_t row, uint32_t col) const
+{
+ return *(_base + getElementOffset(ch, row, col));
+}
+
+float &FeatureView<float>::at(uint32_t ch, uint32_t row, uint32_t col)
+{
+ return *(_base + getElementOffset(ch, row, col));
+}
+
+} // namespace tflite
+} // namespace support
+} // namespace nnfw
diff --git a/libs/support/tflite/src/TensorView.cpp b/libs/support/tflite/src/TensorView.cpp
new file mode 100644
index 000000000..9e164acc2
--- /dev/null
+++ b/libs/support/tflite/src/TensorView.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/TensorView.h"
+
+#include <cassert>
+
+namespace nnfw
+{
+namespace support
+{
+namespace tflite
+{
+
+TensorView<float>::TensorView(const nnfw::util::tensor::Shape &shape, float *base) : _shape{shape}, _base{base}
+{
+ // Set 'stride'
+ _stride.init(_shape);
+}
+
+float TensorView<float>::at(const nnfw::util::tensor::Index &index) const
+{
+ const auto offset = _stride.offset(index);
+
+ return *(_base + offset);
+}
+
+float &TensorView<float>::at(const nnfw::util::tensor::Index &index)
+{
+ const auto offset = _stride.offset(index);
+
+ return *(_base + offset);
+}
+
+TensorView<float> TensorView<float>::make(::tflite::Interpreter &interp, int tensor_index)
+{
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ // TODO Enable the following assets
+ // assert(isFloatTensor(tensor_ptr));
+ // assert(isFeatureTensor(tensor_ptr));
+
+ // Set 'shape'
+ nnfw::util::tensor::Shape shape(tensor_ptr->dims->size);
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ shape.dim(axis) = tensor_ptr->dims->data[axis];
+ }
+
+ return TensorView<float>(shape, interp.typed_tensor<float>(tensor_index));
+}
+
+} // namespace tflite
+} // namespace support
+} // namespace nnfw
diff --git a/libs/support/tflite/src/TensorView.test.cpp b/libs/support/tflite/src/TensorView.test.cpp
new file mode 100644
index 000000000..75993a6da
--- /dev/null
+++ b/libs/support/tflite/src/TensorView.test.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/TensorView.h"
+
+#include <cassert>
+
+int main(int argc, char **argv)
+{
+ float value[6] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
+
+ const nnfw::util::tensor::Shape shape{2, 3};
+ const nnfw::support::tflite::TensorView<float> view{shape, value};
+
+ assert(view.at(nnfw::util::tensor::Index{0, 0}) == 1.0f);
+ assert(view.at(nnfw::util::tensor::Index{0, 1}) == 2.0f);
+ assert(view.at(nnfw::util::tensor::Index{0, 2}) == 3.0f);
+ assert(view.at(nnfw::util::tensor::Index{1, 0}) == 4.0f);
+ assert(view.at(nnfw::util::tensor::Index{1, 1}) == 5.0f);
+ assert(view.at(nnfw::util::tensor::Index{1, 2}) == 6.0f);
+
+ return 0;
+}
diff --git a/libs/support/tflite/src/interp/FlatBufferBuilder.cpp b/libs/support/tflite/src/interp/FlatBufferBuilder.cpp
new file mode 100644
index 000000000..f46c74652
--- /dev/null
+++ b/libs/support/tflite/src/interp/FlatBufferBuilder.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/interp/FlatBufferBuilder.h"
+
+#include <tensorflow/contrib/lite/kernels/register.h>
+
+namespace nnfw
+{
+namespace support
+{
+namespace tflite
+{
+namespace interp
+{
+
+std::unique_ptr<::tflite::Interpreter> FlatBufferBuilder::build(void) const
+{
+ std::unique_ptr<::tflite::Interpreter> interpreter;
+
+ ::tflite::ops::builtin::BuiltinOpResolver resolver;
+
+ ::tflite::InterpreterBuilder builder(_model, resolver);
+
+ builder(&interpreter);
+
+ return std::move(interpreter);
+}
+
+} // namespace interp
+} // namespace tflite
+} // namespace support
+} // namespace nnfw
diff --git a/libs/support/tflite/src/interp/FunctionBuilder.cpp b/libs/support/tflite/src/interp/FunctionBuilder.cpp
new file mode 100644
index 000000000..65783bd37
--- /dev/null
+++ b/libs/support/tflite/src/interp/FunctionBuilder.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 "support/tflite/interp/FunctionBuilder.h"
+
+namespace nnfw
+{
+namespace support
+{
+namespace tflite
+{
+namespace interp
+{
+
+std::unique_ptr<::tflite::Interpreter> FunctionBuilder::build(void) const
+{
+ auto res = std::unique_ptr<::tflite::Interpreter>{new ::tflite::Interpreter};
+
+ _fn(*res);
+
+ return std::move(res);
+}
+
+} // namespace interp
+} // namespace tflite
+} // namespace support
+} // namespace nnfw