openvino/ngraph/core/src/util.cpp

710 lines
18 KiB
C++

//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// 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 <algorithm>
#include <deque>
#include <forward_list>
#include <iomanip>
#include <map>
#include <numeric>
#include <unordered_set>
#include "ngraph/coordinate_diff.hpp"
#include "ngraph/function.hpp"
#include "ngraph/graph_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/node.hpp"
#include "ngraph/op/result.hpp"
#include "ngraph/partial_shape.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/util.hpp"
#include <iostream>
using namespace std;
using namespace ngraph;
void ngraph::dump(ostream& out, const void* _data, size_t _size)
{
auto flags = out.flags();
const uint8_t* data = reinterpret_cast<const uint8_t*>(_data);
size_t len = _size;
size_t index = 0;
while (index < len)
{
out << std::hex << std::setw(8) << std::setfill('0') << index;
for (int i = 0; i < 8; i++)
{
if (index + i < len)
{
out << " " << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<uint32_t>(data[i]);
}
else
{
out << " ";
}
}
out << " ";
for (int i = 8; i < 16; i++)
{
if (index + i < len)
{
out << " " << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<uint32_t>(data[i]);
}
else
{
out << " ";
}
}
out << " ";
for (int i = 0; i < 16; i++)
{
char ch = (index + i < len ? data[i] : ' ');
out << ((ch < 32) ? '.' : ch);
}
out << "\n";
data += 16;
index += 16;
}
out.flags(flags);
}
std::string ngraph::to_lower(const std::string& s)
{
std::string rc = s;
std::transform(rc.begin(), rc.end(), rc.begin(), ::tolower);
return rc;
}
std::string ngraph::to_upper(const std::string& s)
{
std::string rc = s;
std::transform(rc.begin(), rc.end(), rc.begin(), ::toupper);
return rc;
}
string ngraph::trim(const string& s)
{
string rc = s;
// trim trailing spaces
size_t pos = rc.find_last_not_of(" \t");
if (string::npos != pos)
{
rc = rc.substr(0, pos + 1);
}
// trim leading spaces
pos = rc.find_first_not_of(" \t");
if (string::npos != pos)
{
rc = rc.substr(pos);
}
return rc;
}
vector<string> ngraph::split(const string& src, char delimiter, bool do_trim)
{
size_t pos;
string token;
size_t start = 0;
vector<string> rc;
while ((pos = src.find(delimiter, start)) != std::string::npos)
{
token = src.substr(start, pos - start);
start = pos + 1;
if (do_trim)
{
token = trim(token);
}
rc.push_back(token);
}
if (start <= src.size())
{
token = src.substr(start);
if (do_trim)
{
token = trim(token);
}
rc.push_back(token);
}
return rc;
}
size_t ngraph::hash_combine(const std::vector<size_t>& list)
{
size_t seed = 0;
for (size_t v : list)
{
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
void* ngraph::ngraph_malloc(size_t size)
{
auto ptr = malloc(size);
if (size != 0 && !ptr)
{
NGRAPH_ERR << "malloc failed to allocate memory of size " << size;
throw std::bad_alloc();
}
return ptr;
}
void ngraph::ngraph_free(void* ptr)
{
if (ptr)
{
free(ptr);
}
}
size_t ngraph::round_up(size_t size, size_t alignment)
{
if (alignment == 0)
{
return size;
}
size_t remainder = size % alignment;
if (remainder == 0)
{
return size;
}
return size + alignment - remainder;
}
size_t stopwatch::get_call_count() const
{
return m_total_count;
}
size_t stopwatch::get_seconds() const
{
return chrono::duration_cast<chrono::seconds>(get_timer_value()).count();
}
size_t stopwatch::get_milliseconds() const
{
return chrono::duration_cast<chrono::milliseconds>(get_timer_value()).count();
}
size_t stopwatch::get_microseconds() const
{
return chrono::duration_cast<chrono::microseconds>(get_timer_value()).count();
}
size_t stopwatch::get_nanoseconds() const
{
return get_timer_value().count();
}
chrono::nanoseconds stopwatch::get_timer_value() const
{
if (m_active)
{
return (m_clock.now() - m_start_time);
}
else
{
return m_last_time;
}
}
size_t stopwatch::get_total_seconds() const
{
return chrono::duration_cast<chrono::seconds>(m_total_time).count();
}
size_t stopwatch::get_total_milliseconds() const
{
return chrono::duration_cast<chrono::milliseconds>(m_total_time).count();
}
size_t stopwatch::get_total_microseconds() const
{
return chrono::duration_cast<chrono::microseconds>(m_total_time).count();
}
size_t stopwatch::get_total_nanoseconds() const
{
return m_total_time.count();
}
namespace ngraph
{
template <>
float parse_string<float>(const std::string& s)
{
const char* tmp = s.c_str();
char* end;
float result = strtof(tmp, &end);
if (*end != 0)
{
throw std::runtime_error("Could not parse literal '" + s + "'");
}
return result;
}
template <>
double parse_string<double>(const std::string& s)
{
const char* tmp = s.c_str();
char* end;
double result = strtod(tmp, &end);
if (*end != 0)
{
throw std::runtime_error("Could not parse literal '" + s + "'");
}
return result;
}
template <>
int8_t parse_string<int8_t>(const std::string& s)
{
char* err;
int8_t result = strtol(s.c_str(), &err, 10);
// Check that (1) parsing succeeded and (2) the entire string was used.
if (*err != 0)
{
throw std::runtime_error("Could not parse literal '" + s + "'");
}
return result;
}
template <>
uint8_t parse_string<uint8_t>(const std::string& s)
{
char* err;
uint8_t result = strtol(s.c_str(), &err, 10);
// Check that (1) parsing succeeded and (2) the entire string was used.
if (*err != 0)
{
throw std::runtime_error("Could not parse literal '" + s + "'");
}
return result;
}
}
std::ostream& operator<<(std::ostream& os, const ngraph::NodeVector& nv)
{
std::vector<std::string> names;
for (auto n : nv)
{
names.push_back(n->get_name());
}
os << vector_to_string(names);
return os;
}
bool ngraph::is_valid_permutation(ngraph::AxisVector permutation, ngraph::Rank rank)
{
std::vector<bool> axis_occurs(permutation.size(), false);
// Check bounds if rank is static
if (rank.is_static())
{
auto bound = rank.get_length();
for (auto axis : permutation)
{
if (static_cast<decltype(bound)>(axis) >= bound)
{
return false;
}
}
}
for (auto& axis : permutation)
{
axis_occurs[axis] = true;
}
for (size_t axis = 0; axis < permutation.size(); axis++)
{
if (!axis_occurs[axis])
{
return false;
}
}
return (rank.is_dynamic() || permutation.size() == rank.get_length());
}
template <typename T>
T ngraph::apply_permutation(T input, AxisVector order)
{
NGRAPH_CHECK(is_valid_permutation(order, input.size()),
"Permutation ",
order,
" is not valid for ",
input);
T output(input.size());
for (size_t i = 0; i < order.size(); i++)
{
output[i] = input.at(order.at(i));
}
return output;
}
template AxisVector ngraph::apply_permutation<AxisVector>(AxisVector input, AxisVector order);
template Shape ngraph::apply_permutation<Shape>(Shape input, AxisVector order);
template ngraph::Coordinate ngraph::apply_permutation<ngraph::Coordinate>(ngraph::Coordinate input,
ngraph::AxisVector order);
template ngraph::CoordinateDiff
ngraph::apply_permutation<ngraph::CoordinateDiff>(ngraph::CoordinateDiff input,
ngraph::AxisVector order);
template ngraph::Strides ngraph::apply_permutation<ngraph::Strides>(ngraph::Strides input,
ngraph::AxisVector order);
namespace ngraph
{
template <>
PartialShape apply_permutation(PartialShape input, AxisVector order)
{
NGRAPH_CHECK(is_valid_permutation(order, input.rank()),
"Permutation ",
order,
" is not valid for ",
input);
// Here's the special part: if AxisVector is a viable permutation of _some_ rank, and input
// has dynamic rank, we just stick with dynamic rank.
if (input.rank().is_dynamic())
{
return input;
}
PartialShape output{PartialShape::dynamic(order.size())};
for (size_t i = 0; i < order.size(); i++)
{
output[i] = input[order.at(i)];
}
return output;
}
}
AxisVector ngraph::get_default_order(const Shape& shape)
{
return get_default_order(shape.size());
}
AxisVector ngraph::get_default_order(size_t rank)
{
AxisVector default_order(rank);
std::iota(begin(default_order), end(default_order), 0);
return default_order;
}
void ngraph::parse_version_string(
std::string version, size_t& major, size_t& minor, size_t& patch, string& extra)
{
// Since regex is broken in gcc 4.8 I will just manually parse the version string
// Version strings look like `0.25.0-rc.0+7c32240` or `v0.25.0-rc.0+7c32240`
size_t start;
size_t end;
extra = "";
start = (version[0] == 'v' ? 1 : 0);
end = version.find_first_of('.', start);
string major_str = version.substr(start, end - start);
start = end + 1;
end = version.find_first_of('.', start);
string minor_str = version.substr(start, end - start);
start = end + 1;
end = version.find_first_of("-+", start);
string patch_str = version.substr(start, end - start);
start = end;
if (start != string::npos)
{
extra = version.substr(start);
}
size_t err;
bool error = false;
try
{
major = stoi(major_str, &err);
if (err != major_str.size())
{
error = true;
}
minor = stoi(minor_str, &err);
if (err != minor_str.size())
{
error = true;
}
patch = stoi(patch_str, &err);
if (err != patch_str.size())
{
error = true;
}
}
catch (...)
{
error = true;
}
if (error)
{
throw runtime_error("Error parsing version string '" + version + "'");
}
}
vector<float> read_float_vector(shared_ptr<runtime::Tensor> tv)
{
vector<float> float_vec;
element::Type element_type = tv->get_element_type();
if (element_type == element::boolean)
{
vector<char> vec = read_vector<char>(tv);
// Changed from vector ctor to explicit for loop to add static_cast
// This silences MSVC warnings
for (char value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::bf16)
{
vector<bfloat16> vec = read_vector<bfloat16>(tv);
float_vec = bfloat16::to_float_vector(vec);
}
else if (element_type == element::f16)
{
vector<float16> vec = read_vector<float16>(tv);
for (float16 value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::f32)
{
vector<float> vec = read_vector<float>(tv);
for (float value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::f64)
{
vector<double> vec = read_vector<double>(tv);
for (double value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::i8)
{
vector<int8_t> vec = read_vector<int8_t>(tv);
for (int8_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::i16)
{
vector<int16_t> vec = read_vector<int16_t>(tv);
for (int16_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::i32)
{
vector<int32_t> vec = read_vector<int32_t>(tv);
for (int32_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::i64)
{
vector<int64_t> vec = read_vector<int64_t>(tv);
for (int64_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::u8)
{
vector<uint8_t> vec = read_vector<uint8_t>(tv);
for (uint8_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::u16)
{
vector<uint16_t> vec = read_vector<uint16_t>(tv);
for (uint16_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::u32)
{
vector<uint32_t> vec = read_vector<uint32_t>(tv);
for (uint32_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else if (element_type == element::u64)
{
vector<uint64_t> vec = read_vector<uint64_t>(tv);
for (uint64_t value : vec)
{
float_vec.push_back(static_cast<float>(value));
}
}
else
{
throw ngraph_error("Unsupported nGraph element type.");
}
return float_vec;
}
vector<int64_t> read_index_vector(shared_ptr<runtime::Tensor> tv)
{
vector<int64_t> index_vec;
element::Type element_type = tv->get_element_type();
if (element_type == element::boolean)
{
vector<char> vec = read_vector<char>(tv);
// Changed from vector ctor to explicit for loop to add static_cast
// This silences MSVC warnings
for (char value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::bf16)
{
vector<bfloat16> vec = read_vector<bfloat16>(tv);
vector<float> float_vec = bfloat16::to_float_vector(vec);
for (float value : float_vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::f16)
{
vector<float16> vec = read_vector<float16>(tv);
for (float16 value : vec)
{
index_vec.push_back(static_cast<int64_t>(static_cast<float>(value)));
}
}
else if (element_type == element::f32)
{
vector<float> vec = read_vector<float>(tv);
for (float value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::f64)
{
vector<double> vec = read_vector<double>(tv);
for (double value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::i8)
{
vector<int8_t> vec = read_vector<int8_t>(tv);
for (int8_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::i16)
{
vector<int16_t> vec = read_vector<int16_t>(tv);
for (int16_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::i32)
{
vector<int32_t> vec = read_vector<int32_t>(tv);
for (int32_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::i64)
{
index_vec = read_vector<int64_t>(tv);
}
else if (element_type == element::u8)
{
vector<uint8_t> vec = read_vector<uint8_t>(tv);
for (uint8_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::u16)
{
vector<uint16_t> vec = read_vector<uint16_t>(tv);
for (uint16_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::u32)
{
vector<uint32_t> vec = read_vector<uint32_t>(tv);
for (uint32_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else if (element_type == element::u64)
{
vector<uint64_t> vec = read_vector<uint64_t>(tv);
for (uint64_t value : vec)
{
index_vec.push_back(static_cast<int64_t>(value));
}
}
else
{
throw ngraph_error("Unsupported nGraph element type.");
}
return index_vec;
}