Allow avoiding Constant casting / printing VisualizeTree (#19845)
* Avoid Constant casting / printing when OV_VISUALIZE_TREE_CONST_MAX_ELEMENTS==0 Cast only requested amount of elements in Constant::cast_vector<> * Refactor * Revert style back * Fix signed/unsigned comparison * test * Style * Style
This commit is contained in:
committed by
GitHub
parent
215a2f435b
commit
00bc4436a9
@@ -295,10 +295,11 @@ public:
|
||||
|
||||
/// \brief Return the Constant's value as a vector cast to type T
|
||||
///
|
||||
/// \tparam T Type to which data vector's entries will be cast.
|
||||
/// \tparam T Type to which data vector's entries will be cast.
|
||||
/// \param num_elements (Optional) Number of elements to cast. In default case returns all elements
|
||||
/// \return Constant's data vector.
|
||||
template <typename T>
|
||||
std::vector<T> cast_vector() const {
|
||||
std::vector<T> cast_vector(int64_t num_elements = -1) const {
|
||||
auto source_type = get_element_type();
|
||||
std::vector<T> rc;
|
||||
using Type_t = element::Type_t;
|
||||
@@ -306,54 +307,58 @@ public:
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4244)
|
||||
#endif
|
||||
size_t num_elements_in_constant = shape_size(m_shape);
|
||||
size_t num_elements_to_cast =
|
||||
(num_elements < 0 ? num_elements_in_constant
|
||||
: std::min(static_cast<size_t>(num_elements), num_elements_in_constant));
|
||||
switch (source_type) {
|
||||
case Type_t::boolean:
|
||||
cast_vector<Type_t::boolean>(rc);
|
||||
cast_vector<Type_t::boolean>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::bf16:
|
||||
cast_vector<Type_t::bf16>(rc);
|
||||
cast_vector<Type_t::bf16>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::f16:
|
||||
cast_vector<Type_t::f16>(rc);
|
||||
cast_vector<Type_t::f16>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::f32:
|
||||
cast_vector<Type_t::f32>(rc);
|
||||
cast_vector<Type_t::f32>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::f64:
|
||||
cast_vector<Type_t::f64>(rc);
|
||||
cast_vector<Type_t::f64>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::i4:
|
||||
cast_vector<Type_t::i4>(rc);
|
||||
cast_vector<Type_t::i4>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::i8:
|
||||
cast_vector<Type_t::i8>(rc);
|
||||
cast_vector<Type_t::i8>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::i16:
|
||||
cast_vector<Type_t::i16>(rc);
|
||||
cast_vector<Type_t::i16>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::i32:
|
||||
cast_vector<Type_t::i32>(rc);
|
||||
cast_vector<Type_t::i32>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::i64:
|
||||
cast_vector<Type_t::i64>(rc);
|
||||
cast_vector<Type_t::i64>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u1:
|
||||
cast_vector<Type_t::u1>(rc);
|
||||
cast_vector<Type_t::u1>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u4:
|
||||
cast_vector<Type_t::u4>(rc);
|
||||
cast_vector<Type_t::u4>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u8:
|
||||
cast_vector<Type_t::u8>(rc);
|
||||
cast_vector<Type_t::u8>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u16:
|
||||
cast_vector<Type_t::u16>(rc);
|
||||
cast_vector<Type_t::u16>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u32:
|
||||
cast_vector<Type_t::u32>(rc);
|
||||
cast_vector<Type_t::u32>(rc, num_elements_to_cast);
|
||||
break;
|
||||
case Type_t::u64:
|
||||
cast_vector<Type_t::u64>(rc);
|
||||
cast_vector<Type_t::u64>(rc, num_elements_to_cast);
|
||||
break;
|
||||
default:
|
||||
OPENVINO_THROW("unsupported type");
|
||||
@@ -438,15 +443,19 @@ private:
|
||||
typename std::enable_if<Type != element::Type_t::u1 && Type != element::Type_t::u4 &&
|
||||
Type != element::Type_t::i4,
|
||||
bool>::type = true>
|
||||
void cast_vector(std::vector<OUT_T>& output_vector) const {
|
||||
void cast_vector(std::vector<OUT_T>& output_vector, size_t num_elements) const {
|
||||
// this function is workaround for waring during windows building
|
||||
// build complains for vector creation based on iterators
|
||||
// which point on different type than destination vector::value_type
|
||||
using IN_T = fundamental_type_for<Type>;
|
||||
auto source_vector = get_vector<IN_T>();
|
||||
output_vector.reserve(source_vector.size());
|
||||
auto output_size = std::min(num_elements, source_vector.size());
|
||||
output_vector.reserve(output_size);
|
||||
|
||||
std::transform(source_vector.begin(), source_vector.end(), std::back_inserter(output_vector), [](IN_T c) {
|
||||
std::transform(source_vector.begin(),
|
||||
source_vector.begin() + output_size,
|
||||
std::back_inserter(output_vector),
|
||||
[](IN_T c) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# ifdef __has_warning
|
||||
@@ -465,12 +474,13 @@ private:
|
||||
# pragma warning(disable : 4018)
|
||||
# pragma warning(disable : 4804)
|
||||
#endif
|
||||
if (!std::is_same<OUT_T, IN_T>::value) {
|
||||
OPENVINO_ASSERT(!std::numeric_limits<IN_T>::is_signed || std::numeric_limits<OUT_T>::lowest() <= c,
|
||||
"Cannot cast vector from constant. Some values are outside the range.");
|
||||
OPENVINO_ASSERT(std::numeric_limits<OUT_T>::max() >= c,
|
||||
"Cannot cast vector from constant. Some values are outside the range.");
|
||||
}
|
||||
if (!std::is_same<OUT_T, IN_T>::value) {
|
||||
OPENVINO_ASSERT(
|
||||
!std::numeric_limits<IN_T>::is_signed || std::numeric_limits<OUT_T>::lowest() <= c,
|
||||
"Cannot cast vector from constant. Some values are outside the range.");
|
||||
OPENVINO_ASSERT(std::numeric_limits<OUT_T>::max() >= c,
|
||||
"Cannot cast vector from constant. Some values are outside the range.");
|
||||
}
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
@@ -478,16 +488,16 @@ private:
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
return static_cast<OUT_T>(c);
|
||||
});
|
||||
return static_cast<OUT_T>(c);
|
||||
});
|
||||
}
|
||||
|
||||
template <element::Type_t Type,
|
||||
typename OUT_T,
|
||||
typename std::enable_if<Type == element::Type_t::u1, bool>::type = true>
|
||||
void cast_vector(std::vector<OUT_T>& output) const {
|
||||
void cast_vector(std::vector<OUT_T>& output, size_t num_elements) const {
|
||||
using IN_T = fundamental_type_for<Type>;
|
||||
const auto element_number = shape_size(m_shape);
|
||||
const auto element_number = std::min(num_elements, shape_size(m_shape));
|
||||
const auto source_begin = get_data_ptr<uint8_t>();
|
||||
const auto source_end = std::next(source_begin, (element_number + 7) / 8);
|
||||
const auto round_element_no = element_number % 8 ? element_number - element_number % 8 + 8 : element_number;
|
||||
@@ -504,9 +514,9 @@ private:
|
||||
template <element::Type_t Type,
|
||||
typename OUT_T,
|
||||
typename std::enable_if<Type == element::Type_t::u4, bool>::type = true>
|
||||
void cast_vector(std::vector<OUT_T>& output) const {
|
||||
void cast_vector(std::vector<OUT_T>& output, size_t num_elements) const {
|
||||
using IN_T = fundamental_type_for<Type>;
|
||||
const auto element_number = shape_size(m_shape);
|
||||
const auto element_number = std::min(num_elements, shape_size(m_shape));
|
||||
const auto source_begin = get_data_ptr<uint8_t>();
|
||||
const auto source_end = std::next(source_begin, (element_number + 1) / 2);
|
||||
const auto round_element_no = element_number % 2 ? element_number + 1 : element_number;
|
||||
@@ -522,9 +532,9 @@ private:
|
||||
template <element::Type_t Type,
|
||||
typename OUT_T,
|
||||
typename std::enable_if<Type == element::Type_t::i4, bool>::type = true>
|
||||
void cast_vector(std::vector<OUT_T>& output) const {
|
||||
void cast_vector(std::vector<OUT_T>& output, size_t num_elements) const {
|
||||
using IN_T = fundamental_type_for<Type>;
|
||||
const auto element_number = shape_size(m_shape);
|
||||
const auto element_number = std::min(num_elements, shape_size(m_shape));
|
||||
const auto source_begin = get_data_ptr<uint8_t>();
|
||||
const auto source_end = std::next(source_begin, (element_number + 1) / 2);
|
||||
const auto round_element_no = element_number % 2 ? element_number + 1 : element_number;
|
||||
|
||||
@@ -213,8 +213,6 @@ ov::pass::VisualizeTree::VisualizeTree(const std::string& file_name, node_modifi
|
||||
void ov::pass::VisualizeTree::add_node_arguments(std::shared_ptr<Node> node,
|
||||
std::unordered_map<Node*, HeightMap>& height_maps,
|
||||
size_t& fake_node_ctr) {
|
||||
static const int const_max_elements = ov::util::getenv_int("OV_VISUALIZE_TREE_CONST_MAX_ELEMENTS", 7);
|
||||
|
||||
size_t arg_index = 0;
|
||||
for (auto input_value : node->input_values()) {
|
||||
auto arg = input_value.get_node_shared_ptr();
|
||||
@@ -227,7 +225,7 @@ void ov::pass::VisualizeTree::add_node_arguments(std::shared_ptr<Node> node,
|
||||
"style=\"dashed\"",
|
||||
color,
|
||||
std::string("label=\"") + get_node_name(arg) + std::string("\n") +
|
||||
get_constant_value(arg, const_max_elements) + std::string("\"")};
|
||||
get_constant_value(arg) + std::string("\"")};
|
||||
|
||||
if (m_node_modifiers && !arg->output(0).get_rt_info().empty()) {
|
||||
m_node_modifiers(*arg, attributes);
|
||||
@@ -280,13 +278,7 @@ std::string ov::pass::VisualizeTree::add_attributes(std::shared_ptr<Node> node)
|
||||
|
||||
static std::string pretty_partial_shape(const ov::PartialShape& shape) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (shape.rank().is_dynamic()) {
|
||||
ss << "?";
|
||||
} else {
|
||||
ss << shape;
|
||||
}
|
||||
|
||||
ss << shape;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -327,21 +319,11 @@ static std::string pretty_min_max_denormal_value(const std::vector<T>& values) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string pretty_value(const std::vector<T>& values, size_t max_elements, bool allow_obfuscate = false) {
|
||||
static std::string pretty_value(const std::vector<T>& values, bool allow_obfuscate = false) {
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
if (i < max_elements) {
|
||||
if (i != 0 && i % 8 == 0) {
|
||||
ss << std::endl;
|
||||
}
|
||||
} else {
|
||||
bool all_same = std::all_of(values.begin(), values.end(), [&](const T& el) {
|
||||
return el == values[0];
|
||||
});
|
||||
ss << "..." << (all_same ? " same" : "");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != 0 && i % 8 == 0)
|
||||
ss << std::endl;
|
||||
const auto& value = values[i];
|
||||
if (i > 0)
|
||||
ss << ", ";
|
||||
@@ -361,46 +343,46 @@ static std::string pretty_value(const std::vector<T>& values, size_t max_element
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string get_value(const std::shared_ptr<ov::op::v0::Constant>& constant,
|
||||
size_t max_elements,
|
||||
bool allow_obfuscate = false) {
|
||||
static std::string get_value(const std::shared_ptr<ov::op::v0::Constant>& constant, bool allow_obfuscate = false) {
|
||||
static const int max_elements = ov::util::getenv_int("OV_VISUALIZE_TREE_CONST_MAX_ELEMENTS", 7);
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
switch (constant->get_output_element_type(0)) {
|
||||
case ov::element::Type_t::undefined:
|
||||
ss << "[ undefined value ]";
|
||||
break;
|
||||
case ov::element::Type_t::dynamic:
|
||||
ss << "[ dynamic value ]";
|
||||
break;
|
||||
case ov::element::Type_t::u1:
|
||||
ss << "[ u1 value ]";
|
||||
break;
|
||||
case ov::element::Type_t::u4:
|
||||
ss << "[ u4 value ]";
|
||||
break;
|
||||
case ov::element::Type_t::i4:
|
||||
ss << "[ i4 value ]";
|
||||
ss << constant->get_output_element_type(0).get_type_name() << " value";
|
||||
break;
|
||||
case ov::element::Type_t::bf16:
|
||||
case ov::element::Type_t::f16:
|
||||
case ov::element::Type_t::f32:
|
||||
case ov::element::Type_t::f64:
|
||||
ss << "[" << pretty_value(constant->cast_vector<double>(), max_elements, allow_obfuscate) << "]";
|
||||
ss << pretty_value(constant->cast_vector<double>(max_elements), allow_obfuscate);
|
||||
break;
|
||||
case ov::element::Type_t::i8:
|
||||
case ov::element::Type_t::i16:
|
||||
case ov::element::Type_t::i32:
|
||||
case ov::element::Type_t::i64:
|
||||
ss << "[" << pretty_value(constant->cast_vector<int64_t>(), max_elements, allow_obfuscate) << "]";
|
||||
ss << pretty_value(constant->cast_vector<int64_t>(max_elements), allow_obfuscate);
|
||||
break;
|
||||
case ov::element::Type_t::boolean:
|
||||
case ov::element::Type_t::u8:
|
||||
case ov::element::Type_t::u16:
|
||||
case ov::element::Type_t::u32:
|
||||
case ov::element::Type_t::u64:
|
||||
ss << "[" << pretty_value(constant->cast_vector<uint64_t>(), max_elements, allow_obfuscate) << "]";
|
||||
ss << pretty_value(constant->cast_vector<uint64_t>(max_elements), allow_obfuscate);
|
||||
break;
|
||||
}
|
||||
const auto num_elements_in_constant = static_cast<int>(shape_size(constant->get_shape()));
|
||||
if (num_elements_in_constant == 0)
|
||||
ss << "empty";
|
||||
else if (max_elements == 0)
|
||||
ss << "suppressed";
|
||||
else if (num_elements_in_constant > max_elements)
|
||||
ss << ", ...";
|
||||
ss << " ]";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -418,12 +400,9 @@ static std::string get_bounds_and_label_info(const ov::Output<ov::Node> output)
|
||||
if (size == 0) {
|
||||
label << "empty";
|
||||
} else {
|
||||
static const int const_max_elements = ov::util::getenv_int("OV_VISUALIZE_TREE_CONST_MAX_ELEMENTS", 7);
|
||||
label << " lower: "
|
||||
<< (lower ? get_value(std::make_shared<ov::op::v0::Constant>(lower), const_max_elements, true) : "NONE");
|
||||
label << " upper: "
|
||||
<< (upper ? get_value(std::make_shared<ov::op::v0::Constant>(upper), const_max_elements, true) : "NONE");
|
||||
label << " label: " << (value_label.empty() ? "NONE" : pretty_value(value_label, const_max_elements));
|
||||
label << " lower: " << (lower ? get_value(std::make_shared<ov::op::v0::Constant>(lower), true) : "NONE");
|
||||
label << " upper: " << (upper ? get_value(std::make_shared<ov::op::v0::Constant>(upper), true) : "NONE");
|
||||
label << " label: " << (value_label.empty() ? "NONE" : pretty_value(value_label));
|
||||
}
|
||||
return label.str();
|
||||
}
|
||||
|
||||
@@ -1779,3 +1779,43 @@ TEST(constant, lazy_bitwise_identical) {
|
||||
// '10' times is guaranteed to be faster here (typical value is ~200'000)
|
||||
EXPECT_GT(bitwise_check_count_only, bitwise_check_count * 10);
|
||||
}
|
||||
|
||||
TEST(constant, cast_vector) {
|
||||
std::vector<element::Type_t> types = {element::boolean,
|
||||
element::bf16,
|
||||
element::f16,
|
||||
element::f32,
|
||||
element::f64,
|
||||
element::i4,
|
||||
element::i8,
|
||||
element::i16,
|
||||
element::i32,
|
||||
element::i64,
|
||||
element::u1,
|
||||
element::u4,
|
||||
element::u8,
|
||||
element::u16,
|
||||
element::u32,
|
||||
element::u64};
|
||||
std::vector<int64_t> data = {0, 1, 0, 0, 1, 1, 0, 1};
|
||||
std::vector<int64_t> expected_partial_data = {0, 1, 0, 0, 1, 1};
|
||||
|
||||
for (const auto& type : types) {
|
||||
const auto& constant = op::v0::Constant::create(type, Shape{data.size()}, data);
|
||||
|
||||
const auto& default_casted = constant->cast_vector<int64_t>();
|
||||
EXPECT_EQ(default_casted, data) << "Constant::cast_vector failed default casting for type " << type;
|
||||
|
||||
int64_t num_elements_for_partial_casting = static_cast<int64_t>(expected_partial_data.size());
|
||||
const auto& partially_casted = constant->cast_vector<int64_t>(num_elements_for_partial_casting);
|
||||
EXPECT_EQ(partially_casted, expected_partial_data)
|
||||
<< "Constant::cast_vector failed partial casting for type " << type;
|
||||
|
||||
int64_t num_elements_for_over_casting = static_cast<int64_t>(data.size()) + 10;
|
||||
const auto& over_casted = constant->cast_vector<int64_t>(num_elements_for_over_casting);
|
||||
EXPECT_EQ(over_casted, data) << "Constant::cast_vector failed for partial casting for type " << type;
|
||||
|
||||
EXPECT_TRUE(constant->cast_vector<int64_t>(0).empty())
|
||||
<< "Constant::cast_vector failed empty casting for type " << type;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user