260 lines
9.9 KiB
C++
260 lines
9.9 KiB
C++
// Copyright (C) 2018-2021 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <cmath>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
#include "interpreter_engine.hpp"
|
|
#include "shared_utils.hpp"
|
|
|
|
using namespace ngraph;
|
|
|
|
namespace
|
|
{
|
|
template <typename T>
|
|
typename std::enable_if<std::is_floating_point<T>::value, testing::AssertionResult>::type
|
|
compare_values(const std::shared_ptr<ngraph::op::Constant>& expected_results,
|
|
const std::shared_ptr<ngraph::runtime::Tensor>& results,
|
|
const size_t tolerance_bits)
|
|
{
|
|
const auto expected = expected_results->get_vector<T>();
|
|
const auto result = read_vector<T>(results);
|
|
|
|
return ngraph::test::all_close_f(expected, result, tolerance_bits);
|
|
}
|
|
|
|
testing::AssertionResult
|
|
compare_with_fp_tolerance(const std::shared_ptr<ngraph::op::Constant>& expected_results,
|
|
const std::shared_ptr<ngraph::runtime::Tensor>& results,
|
|
const float tolerance)
|
|
{
|
|
auto comparison_result = testing::AssertionSuccess();
|
|
|
|
const auto expected = expected_results->get_vector<float>();
|
|
const auto result = read_vector<float>(results);
|
|
|
|
return ngraph::test::compare_with_tolerance(expected, result, tolerance);
|
|
}
|
|
|
|
template <typename T>
|
|
typename std::enable_if<std::is_integral<T>::value, testing::AssertionResult>::type
|
|
compare_values(const std::shared_ptr<ngraph::op::Constant>& expected_results,
|
|
const std::shared_ptr<ngraph::runtime::Tensor>& results,
|
|
const size_t)
|
|
{
|
|
const auto expected = expected_results->get_vector<T>();
|
|
const auto result = read_vector<T>(results);
|
|
|
|
return ngraph::test::all_close(expected, result);
|
|
}
|
|
|
|
// used for float16 and bfloat 16 comparisons
|
|
template <typename T>
|
|
typename std::enable_if<std::is_class<T>::value, testing::AssertionResult>::type
|
|
compare_values(const std::shared_ptr<ngraph::op::Constant>& expected_results,
|
|
const std::shared_ptr<ngraph::runtime::Tensor>& results,
|
|
const size_t tolerance_bits)
|
|
{
|
|
const auto expected = expected_results->get_vector<T>();
|
|
const auto result = read_vector<T>(results);
|
|
|
|
// TODO: add testing infrastructure for float16 and bfloat16 to avoid cast to double
|
|
std::vector<double> expected_double(expected.size());
|
|
std::vector<double> result_double(result.size());
|
|
|
|
NGRAPH_CHECK(expected.size() == result.size(),
|
|
"Number of expected and computed results don't match");
|
|
|
|
for (size_t i = 0; i < expected.size(); ++i)
|
|
{
|
|
expected_double[i] = static_cast<double>(expected[i]);
|
|
result_double[i] = static_cast<double>(result[i]);
|
|
}
|
|
|
|
return ngraph::test::all_close_f(expected_double, result_double, tolerance_bits);
|
|
}
|
|
}; // namespace
|
|
|
|
test::INTERPRETER_Engine::INTERPRETER_Engine(const std::shared_ptr<Function> function)
|
|
: m_function{function}
|
|
{
|
|
m_backend = ngraph::runtime::Backend::create(NG_BACKEND_NAME, false); // static INT backend
|
|
m_executable = m_backend->compile(m_function);
|
|
for (size_t i = 0; i < m_function->get_output_size(); ++i)
|
|
{
|
|
m_result_tensors.push_back(m_backend->create_tensor(m_function->get_output_element_type(i),
|
|
m_function->get_output_shape(i)));
|
|
}
|
|
}
|
|
|
|
test::INTERPRETER_Engine::INTERPRETER_Engine(const std::shared_ptr<Function> function,
|
|
INTERPRETER_Engine::DynamicBackendTag)
|
|
: m_function{function}
|
|
{
|
|
m_backend = ngraph::runtime::Backend::create(NG_BACKEND_NAME, true); // dynamic INT backend
|
|
m_executable = m_backend->compile(m_function);
|
|
for (size_t i = 0; i < m_function->get_output_size(); ++i)
|
|
{
|
|
m_result_tensors.push_back(m_backend->create_dynamic_tensor(
|
|
m_function->get_output_element_type(i), m_function->get_output_partial_shape(i)));
|
|
}
|
|
}
|
|
|
|
test::INTERPRETER_Engine test::INTERPRETER_Engine::dynamic(const std::shared_ptr<Function> function)
|
|
{
|
|
return INTERPRETER_Engine{function, DynamicBackendTag{}};
|
|
}
|
|
|
|
void test::INTERPRETER_Engine::infer()
|
|
{
|
|
const auto& function_results = m_function->get_results();
|
|
NGRAPH_CHECK(m_expected_outputs.size() == function_results.size(),
|
|
"Expected number of outputs is different from the function's number "
|
|
"of results.");
|
|
m_executable->call_with_validate(m_result_tensors, m_input_tensors);
|
|
}
|
|
|
|
testing::AssertionResult
|
|
test::INTERPRETER_Engine::compare_results_with_tolerance_as_fp(const float tolerance)
|
|
{
|
|
auto comparison_result = testing::AssertionSuccess();
|
|
|
|
for (size_t i = 0; i < m_expected_outputs.size(); ++i)
|
|
{
|
|
const auto& result_tensor = m_result_tensors.at(i);
|
|
const auto& expected_result_constant = m_expected_outputs.at(i);
|
|
const auto& element_type = result_tensor->get_element_type();
|
|
|
|
const auto& expected_shape = expected_result_constant->get_shape();
|
|
const auto& result_shape = result_tensor->get_shape();
|
|
|
|
if (expected_shape != result_shape)
|
|
{
|
|
comparison_result = testing::AssertionFailure();
|
|
comparison_result << "Computed data shape(" << result_shape
|
|
<< ") does not match the expected shape(" << expected_shape
|
|
<< ") for output " << i << std::endl;
|
|
break;
|
|
}
|
|
|
|
switch (element_type)
|
|
{
|
|
case element::Type_t::f32:
|
|
comparison_result =
|
|
compare_with_fp_tolerance(expected_result_constant, result_tensor, tolerance);
|
|
break;
|
|
default:
|
|
comparison_result = testing::AssertionFailure()
|
|
<< "Unsupported data type encountered in "
|
|
"'compare_results_with_tolerance_as_fp' method";
|
|
}
|
|
|
|
if (comparison_result == testing::AssertionFailure())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return comparison_result;
|
|
}
|
|
|
|
testing::AssertionResult test::INTERPRETER_Engine::compare_results(const size_t tolerance_bits)
|
|
{
|
|
auto comparison_result = testing::AssertionSuccess();
|
|
|
|
for (size_t i = 0; i < m_expected_outputs.size(); ++i)
|
|
{
|
|
const auto& result_tensor = m_result_tensors.at(i);
|
|
const auto& expected_result_constant = m_expected_outputs.at(i);
|
|
const auto& element_type = result_tensor->get_element_type();
|
|
|
|
const auto& expected_shape = expected_result_constant->get_shape();
|
|
const auto& result_shape = result_tensor->get_shape();
|
|
|
|
if (expected_shape != result_shape)
|
|
{
|
|
comparison_result = testing::AssertionFailure();
|
|
comparison_result << "Computed data shape(" << result_shape
|
|
<< ") does not match the expected shape(" << expected_shape
|
|
<< ") for output " << i << std::endl;
|
|
break;
|
|
}
|
|
|
|
switch (element_type)
|
|
{
|
|
case element::Type_t::f16:
|
|
comparison_result = compare_values<ngraph::float16>(
|
|
expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::bf16:
|
|
comparison_result = compare_values<ngraph::bfloat16>(
|
|
expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::f32:
|
|
comparison_result =
|
|
compare_values<float>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::f64:
|
|
comparison_result =
|
|
compare_values<double>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::i8:
|
|
comparison_result =
|
|
compare_values<int8_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::i16:
|
|
comparison_result =
|
|
compare_values<int16_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::i32:
|
|
comparison_result =
|
|
compare_values<int32_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::i64:
|
|
comparison_result =
|
|
compare_values<int64_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::u8:
|
|
comparison_result =
|
|
compare_values<uint8_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::u16:
|
|
comparison_result =
|
|
compare_values<uint16_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::u32:
|
|
comparison_result =
|
|
compare_values<uint32_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::u64:
|
|
comparison_result =
|
|
compare_values<uint64_t>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
case element::Type_t::boolean:
|
|
comparison_result =
|
|
compare_values<char>(expected_result_constant, result_tensor, tolerance_bits);
|
|
break;
|
|
default:
|
|
comparison_result = testing::AssertionFailure()
|
|
<< "Unsupported data type encountered in 'compare_results' method";
|
|
}
|
|
|
|
if (comparison_result == testing::AssertionFailure())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return comparison_result;
|
|
}
|
|
|
|
void test::INTERPRETER_Engine::reset()
|
|
{
|
|
m_input_index = 0;
|
|
m_output_index = 0;
|
|
m_expected_outputs.clear();
|
|
m_input_tensors.clear();
|
|
}
|