Enhance compatibility with proto3 and replace or abstract has_*() methods. (#1778)

Enhance proto3 compatibility.
  Replace has_*() method to corresponding enum handling so we can deal with
  proto3 generated stream from proto2 code.
  Add utility wrappers for remaining has_*() methods so we can
  easily deal with them if/when we switch to proto3.
This commit is contained in:
Dmitri Smirnov 2019-09-09 14:07:30 -07:00 committed by GitHub
parent 6a5b11756b
commit 75f241d02c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 428 additions and 270 deletions

View file

@ -227,14 +227,14 @@ bool ShapeHasValue(const NodeArg* def, int i) {
ORT_ENFORCE_DEBUG(nullptr != def);
ORT_ENFORCE_DEBUG(i >= 0);
ORT_ENFORCE_DEBUG(i < def->Shape()->dim_size());
return def->Shape()->dim(i).has_dim_value();
return utils::HasDimValue(def->Shape()->dim(i));
}
bool ShapeHasSymbol(const NodeArg* def, int i) {
ORT_ENFORCE_DEBUG(nullptr != def);
ORT_ENFORCE_DEBUG(i >= 0);
ORT_ENFORCE_DEBUG(i < def->Shape()->dim_size());
return def->Shape()->dim(i).has_dim_param();
return utils::HasDimParam(def->Shape()->dim(i));
}
int64_t ShapeValue(const NodeArg* def, int i) {

View file

@ -6,6 +6,7 @@
#include "core/codegen/mti/mti_tvm_utils.h"
#include "core/codegen/mti/tensor/slice.h"
#include "core/framework/op_kernel_info.h"
#include "core/framework/tensorprotoutils.h"
#include <tvm/ir_pass.h>
@ -42,7 +43,7 @@ Status SliceCommon(const tvm::Array<tvm::Tensor>& inputs,
bool found_in_axes = (axes_iter != axes.end());
if (!found_in_axes) {
tvm_starts.push_back(0);
if (proto_dim.has_dim_value()) {
if (utils::HasDimValue(proto_dim)) {
tvm_ends.push_back(proto_dim.dim_value());
} else {
tvm_ends.push_back(max_range);
@ -51,7 +52,7 @@ Status SliceCommon(const tvm::Array<tvm::Tensor>& inputs,
auto axes_index = axes_iter - axes.begin();
int64_t start = starts[axes_index];
int64_t end = ends[axes_index];
if (proto_dim.has_dim_value()) {
if (utils::HasDimValue(proto_dim)) {
int64_t dim_max = proto_dim.dim_value();
if (start < 0) start += dim_max;
if (end < 0) end += dim_max;

View file

@ -5,6 +5,7 @@
#include "core/codegen/common/profile.h"
#include "core/codegen/passes/utils/codegen_context.h"
#include "core/framework/tensorprotoutils.h"
#include "core/providers/common.h"
#include "gsl/gsl_util"
@ -89,9 +90,9 @@ tvm::Array<tvm::Expr> ShapeToTvmArray(const NodeArg* def, CodeGenContext& ctx) {
}
tvm::Expr ShapeDimToTvmDim(const ONNX_NAMESPACE::TensorShapeProto_Dimension& dim, CodeGenContext& ctx) {
if (dim.has_dim_param()) {
if (utils::HasDimParam(dim)) {
return ctx.GetOrCreateDynamicDim(dim.dim_param());
} else if (dim.has_dim_value()) {
} else if (utils::HasDimValue(dim)) {
return tvm::Expr(gsl::narrow_cast<int32_t>(dim.dim_value()));
}
return ctx.GetOrCreateDynamicDim(ctx.CreateUnnamedSymbol());

View file

@ -13,6 +13,7 @@
#include "core/framework/mldata_type_utils.h"
#include "core/framework/op_kernel.h"
#include "core/framework/session_state.h"
#include "core/framework/tensorprotoutils.h"
#include "core/framework/utils.h"
using namespace onnxruntime::common;
@ -250,14 +251,16 @@ class PlannerImpl {
static bool SameShape(const TensorShapeProto& shape1, const TensorShapeProto& shape2) {
// TODO: This should probably be defined to be the equality operator on TensorShapeProto.
namespace on = ONNX_NAMESPACE;
int rank1 = shape1.dim_size();
if (shape2.dim_size() != rank1) return false;
for (int i = 0; i < rank1; i++) {
const auto& val1 = shape1.dim(i);
const auto& val2 = shape2.dim(i);
if (val1.has_dim_value() && val2.has_dim_value() && (val1.dim_value() == val2.dim_value()))
if (utils::HasDimValue(val1) && utils::HasDimValue(val2) &&
(val1.dim_value() == val2.dim_value()))
continue; // same known dimension
if (val1.has_dim_param() && val2.has_dim_param()) {
if (utils::HasDimParam(val1) && utils::HasDimParam(val2)) {
const auto& val1_param = val1.dim_param();
if (val1_param == val2.dim_param() && !val1_param.empty())
continue; // same unknown dimension
@ -675,7 +678,7 @@ class PlannerImpl {
// TODO: unclear why we should go through a string-representation of type
auto ptype = nodearg.Type();
auto& type_proto = ONNX_NAMESPACE::Utils::DataTypeUtils::ToTypeProto(ptype);
return !type_proto.has_tensor_type();
return !utils::HasTensorType(type_proto);
}
}; // namespace onnxruntime

View file

@ -23,12 +23,17 @@
using namespace ONNX_NAMESPACE;
namespace onnxruntime {
// Return the MLDataType used for a generic Tensor
template <>
MLDataType DataTypeImpl::GetType<Tensor>() {
return TensorTypeBase::Type();
}
} // namespace onnxruntime
// This conflics with the above GetType<>() specialization
#include "core/framework/tensorprotoutils.h"
namespace onnxruntime {
// Return the MLDataType used for a generic SparseTensor
template <>
@ -180,8 +185,7 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Opaque& opaque_proto,
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Tensor& tensor_proto,
const ONNX_NAMESPACE::TypeProto_Tensor& type_proto) {
return type_proto.has_elem_type() &&
type_proto.elem_type() == tensor_proto.elem_type();
return type_proto.elem_type() == tensor_proto.elem_type();
/* Currently all Tensors with all kinds of shapes
are mapped into the same MLDataType (same element type)
so we omit shape from IsCompatible consideration
@ -190,10 +194,6 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Tensor& tensor_proto,
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Map& map_proto,
const ONNX_NAMESPACE::TypeProto_Map& type_proto) {
if (!(type_proto.has_key_type() &&
type_proto.key_type() == map_proto.key_type())) {
return false;
}
const auto& lhs = map_proto;
const auto& rhs = type_proto;
bool result = true;
@ -230,8 +230,7 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Sequence& sequence_proto,
bool result = true;
const auto& lhs = sequence_proto;
const auto& rhs = type_proto;
if (rhs.has_elem_type() &&
lhs.elem_type().value_case() == rhs.elem_type().value_case()) {
if (lhs.elem_type().value_case() == rhs.elem_type().value_case()) {
switch (lhs.elem_type().value_case()) {
case TypeProto::ValueCase::kTensorType:
result = IsCompatible(lhs.elem_type().tensor_type(), rhs.elem_type().tensor_type());
@ -260,16 +259,16 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Sequence& sequence_proto,
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Opaque& opaque_proto, const ONNX_NAMESPACE::TypeProto_Opaque& type_proto) {
const auto& lhs = opaque_proto;
const auto& rhs = type_proto;
bool lhs_domain = lhs.has_domain() && !lhs.domain().empty();
bool rhs_domain = rhs.has_domain() && !rhs.domain().empty();
bool lhs_domain = utils::HasDomain(lhs);
bool rhs_domain = utils::HasDomain(rhs);
if ((lhs_domain != rhs_domain) ||
(lhs_domain && rhs_domain && lhs.domain() != lhs.domain())) {
return false;
}
bool lhs_name = lhs.has_name() && !lhs.name().empty();
bool rhs_name = rhs.has_name() && !rhs.name().empty();
bool lhs_name = utils::HasName(lhs);
bool rhs_name = utils::HasName(rhs);
return !((lhs_name != rhs_name) ||
(lhs_name && rhs_name && lhs.name() != rhs.name()));
@ -277,9 +276,7 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Opaque& opaque_proto, const ON
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_SparseTensor& tensor_proto,
const ONNX_NAMESPACE::TypeProto_SparseTensor& type_proto) {
return type_proto.has_elem_type() &&
type_proto.elem_type() == tensor_proto.elem_type();
// XXX: Ignoring shape for now
return type_proto.elem_type() == tensor_proto.elem_type();
}
void RegisterAllProtos(const std::function<void(MLDataType)>& /*reg_fn*/);
@ -370,16 +367,17 @@ ONNX_NAMESPACE::TypeProto& TensorTypeBase::mutable_type_proto() {
bool TensorTypeBase::IsCompatible(const ONNX_NAMESPACE::TypeProto& type_proto) const {
const auto* thisProto = GetTypeProto();
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kTensorType);
ORT_ENFORCE(utils::HasElemType(thisProto->tensor_type()));
if (&type_proto == thisProto) {
return true;
}
if (type_proto.value_case() != TypeProto::ValueCase::kTensorType) {
return false;
}
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kTensorType);
ORT_ENFORCE(thisProto->tensor_type().has_elem_type());
return data_types_internal::IsCompatible(thisProto->tensor_type(), type_proto.tensor_type());
}
@ -408,7 +406,7 @@ bool SparseTensorTypeBase::IsCompatible(const ONNX_NAMESPACE::TypeProto& type_pr
}
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kSparseTensorType);
ORT_ENFORCE(thisProto->sparse_tensor_type().has_elem_type());
ORT_ENFORCE(utils::HasElemType(thisProto->sparse_tensor_type()));
return data_types_internal::IsCompatible(thisProto->sparse_tensor_type(), type_proto.sparse_tensor_type());
}
@ -461,8 +459,8 @@ bool NonTensorTypeBase::IsMapCompatible(const ONNX_NAMESPACE::TypeProto& type_pr
return false;
}
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kMapType);
ORT_ENFORCE(thisProto->map_type().has_key_type());
ORT_ENFORCE(thisProto->map_type().has_value_type());
ORT_ENFORCE(utils::HasKeyType(thisProto->map_type()));
ORT_ENFORCE(utils::HasKeyType(thisProto->map_type()));
return data_types_internal::IsCompatible(thisProto->map_type(), type_proto.map_type());
}
@ -475,7 +473,7 @@ bool NonTensorTypeBase::IsSequenceCompatible(const ONNX_NAMESPACE::TypeProto& ty
return false;
}
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kSequenceType);
ORT_ENFORCE(thisProto->sequence_type().has_elem_type());
ORT_ENFORCE(utils::HasElemType(thisProto->sequence_type()));
return data_types_internal::IsCompatible(thisProto->sequence_type(), type_proto.sequence_type());
}
@ -488,8 +486,6 @@ bool NonTensorTypeBase::IsOpaqueCompatible(const ONNX_NAMESPACE::TypeProto& type
return false;
}
ORT_ENFORCE(thisProto->value_case() == TypeProto::ValueCase::kOpaqueType);
ORT_ENFORCE(thisProto->opaque_type().has_domain());
ORT_ENFORCE(thisProto->opaque_type().has_name());
return data_types_internal::IsCompatible(thisProto->opaque_type(), type_proto.opaque_type());
}
@ -743,12 +739,12 @@ MLDataType DataTypeImpl::TypeFromProto(const ONNX_NAMESPACE::TypeProto& proto) {
switch (proto.value_case()) {
case TypeProto::ValueCase::kTensorType: {
const auto& tensor_type = proto.tensor_type();
ORT_ENFORCE(tensor_type.has_elem_type());
ORT_ENFORCE(utils::HasElemType(tensor_type));
return TensorTypeFromONNXEnum(tensor_type.elem_type());
} break; // kTensorType
case TypeProto::ValueCase::kSparseTensorType: {
const auto& sparse_tensor_type = proto.sparse_tensor_type();
ORT_ENFORCE(sparse_tensor_type.has_elem_type());
ORT_ENFORCE(utils::HasElemType(sparse_tensor_type));
return SparseTensorTypeFromONNXEnum(sparse_tensor_type.elem_type());
} break; // kSparseTensorType
case TypeProto::ValueCase::kMapType: {

View file

@ -195,7 +195,7 @@ common::Status SaveInitializedTensors(const Env& env, const std::basic_string<PA
//3. create weight tensors based on weights buffer
for (const auto& entry : id_to_initialized_tensor) {
int ort_value_index = entry.first;
const char* name = entry.second->has_name() ? entry.second->name().c_str() : "";
const char* name = (entry.second->name().empty()) ? "" : entry.second->name().c_str();
const ONNX_NAMESPACE::TensorProto& tensor_proto = *(entry.second);
std::unique_ptr<MemBuffer> m;

View file

@ -4,6 +4,7 @@
#include "core/framework/tensor_shape.h"
#include <iostream>
#include "core/common/common.h"
#include "core/framework/tensorprotoutils.h"
#include "core/graph/onnx_protobuf.h"
namespace onnxruntime {
@ -104,9 +105,9 @@ std::ostream& operator<<(std::ostream& out, const ONNX_NAMESPACE::TensorShapePro
result.append(",");
}
if (dim.has_dim_value())
if (utils::HasDimValue(dim))
result.append(std::to_string(dim.dim_value()));
else if (dim.has_dim_param())
else if (utils::HasDimParam(dim))
result.append(dim.dim_param());
first = false;

View file

@ -278,7 +278,7 @@ TensorShape GetTensorShapeFromTensorShapeProto(const ONNX_NAMESPACE::TensorShape
const auto& dims = tensor_shape_proto.dim();
std::vector<int64_t> tensor_shape_vec(static_cast<size_t>(dims.size()));
for (int i = 0; i < dims.size(); ++i) {
tensor_shape_vec[i] = dims[i].has_dim_value() ? dims[i].dim_value()
tensor_shape_vec[i] = HasDimValue(dims[i]) ? dims[i].dim_value()
: -1; /* symbolic dimensions are represented as -1 in onnxruntime*/
}
return TensorShape(std::move(tensor_shape_vec));
@ -394,7 +394,7 @@ Status TensorProtoToMLValue(const Env& env, const ORTCHAR_T* tensor_proto_path,
file_data, raw_data_len, deleter_for_file_data.d));
raw_data = file_data;
}
} else if (tensor_proto.has_raw_data()) {
} else if (utils::HasRawData(tensor_proto)) {
if (ele_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING)
return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "string tensor can not have raw data");
raw_data = tensor_proto.raw_data().data();

View file

@ -62,5 +62,145 @@ template <typename T>
Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_data, size_t raw_data_len,
/*out*/ T* p_data, int64_t expected_size);
inline bool HasDimValue(const ONNX_NAMESPACE::TensorShapeProto_Dimension& dim) {
return dim.value_case() == ONNX_NAMESPACE::TensorShapeProto_Dimension::kDimValue;
}
inline bool HasDimParam(const ONNX_NAMESPACE::TensorShapeProto_Dimension& dim) {
return dim.value_case() == ONNX_NAMESPACE::TensorShapeProto_Dimension::kDimParam;
}
inline bool HasTensorType(const ONNX_NAMESPACE::TypeProto& type_proto) {
return type_proto.value_case() == ONNX_NAMESPACE::TypeProto::kTensorType;
}
inline bool HasElemType(const ONNX_NAMESPACE::TypeProto_Tensor& ten_proto) {
return ten_proto.elem_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED;
;
}
inline bool HasShape(const ONNX_NAMESPACE::TypeProto_Tensor& ten_proto) {
// XXX: Figure out how do in proto3
return ten_proto.has_shape();
}
inline bool HasShape(const ONNX_NAMESPACE::TypeProto_SparseTensor& ten_proto) {
// XXX: Figure out how do in proto3
return ten_proto.has_shape();
}
inline bool HasRawData(const ONNX_NAMESPACE::TensorProto& ten_proto) {
// Can not be UNDEFINED and can not be STRING but test for STRING is usually performed separately
// to return an error
return ten_proto.data_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED &&
ten_proto.has_raw_data(); // XXX: Figure out how to do in proto3
}
inline bool HasDataType(const ONNX_NAMESPACE::TensorProto& ten_proto) {
return ten_proto.data_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED;
}
inline bool HasName(const ONNX_NAMESPACE::TensorProto& ten_proto) {
return ten_proto.has_name(); // XXX
}
inline bool HasElemType(const ONNX_NAMESPACE::TypeProto_Sequence& seq_proto) {
return seq_proto.elem_type().value_case() != ONNX_NAMESPACE::TypeProto::VALUE_NOT_SET;
}
inline bool HasElemType(const ONNX_NAMESPACE::TypeProto_SparseTensor& ten_proto) {
return ten_proto.elem_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED;
}
inline bool HasKeyType(const ONNX_NAMESPACE::TypeProto_Map& map_proto) {
return map_proto.key_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED;
}
inline bool HasValueType(const ONNX_NAMESPACE::TypeProto_Map& map_proto) {
return map_proto.value_type().value_case() != ONNX_NAMESPACE::TypeProto::VALUE_NOT_SET;
}
inline bool HasType(const ONNX_NAMESPACE::ValueInfoProto& vi_proto) {
return vi_proto.type().value_case() != ONNX_NAMESPACE::TypeProto::VALUE_NOT_SET;
}
inline bool HasName(const ONNX_NAMESPACE::ValueInfoProto& vi_proto) {
return vi_proto.has_name(); // XXX: Figure out proto3 way
}
inline bool HasDomain(const ONNX_NAMESPACE::TypeProto_Opaque& op_proto) {
return !op_proto.domain().empty();
}
inline bool HasName(const ONNX_NAMESPACE::TypeProto_Opaque& op_proto) {
return !op_proto.name().empty();
}
inline bool HasType(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() != ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_UNDEFINED;
}
inline bool HasFloat(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_FLOAT;
}
inline bool HasFloats(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_FLOATS;
}
inline bool HasInt(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_INT;
}
inline bool HasInts(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_INTS;
}
inline bool HasString(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_STRING;
}
inline bool HasStrings(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_STRINGS;
}
inline bool HasTensor(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_TENSOR;
}
inline bool HasTensors(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_TENSORS;
}
inline bool HasGraph(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_GRAPH;
}
inline bool HasGraphs(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.type() == ONNX_NAMESPACE::AttributeProto::AttributeType::AttributeProto_AttributeType_GRAPHS;
}
inline bool HasName(const ONNX_NAMESPACE::AttributeProto& at_proto) {
return at_proto.has_name(); // XXX: Fugure out proto3
}
inline bool HasGraph (const ONNX_NAMESPACE::ModelProto& m_proto) {
return m_proto.has_graph(); // XXX proto3
}
inline bool HasIrVersion(const ONNX_NAMESPACE::ModelProto& m_proto) {
return m_proto.has_ir_version(); // XXX proto3
}
inline bool HasModelVersion(const ONNX_NAMESPACE::ModelProto& m_proto) {
return m_proto.has_model_version(); // XXX proto3
}
inline bool HasName(const ONNX_NAMESPACE::NodeProto& node_proto) {
//XXX: Figure out proto3 style
return node_proto.has_name();
}
} // namespace utils
} // namespace onnxruntime

View file

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "core/framework/tensorprotoutils.h"
#include "core/graph/constants.h"
#include "core/graph/contrib_ops/attn_lstm_schema_defs.h"
#include "core/graph/contrib_ops/contrib_defs.h"
@ -643,8 +644,8 @@ and op)DOC";
*output_shape->mutable_dim(static_cast<int>(1)) = input_shape.dim(static_cast<int>(1));
// process 'H' and 'W'
if (!input_shape.dim(static_cast<int>(2)).has_dim_value() ||
!input_shape.dim(static_cast<int>(3)).has_dim_value()) {
if (!utils::HasDimValue(input_shape.dim(static_cast<int>(2))) ||
!utils::HasDimValue(input_shape.dim(static_cast<int>(3)))) {
// either height and width input has symbolic dims, so can't proceed further
// add two dims as placeholders for output_H and output_W and return
output_shape->add_dim();
@ -1254,7 +1255,7 @@ of [N, 0] then [N, 0].
int64_t size = 1;
for (auto& dim : dims) {
if (dim.has_dim_value()) {
if (utils::HasDimValue(dim)) {
size *= dim.dim_value();
}
}
@ -1530,7 +1531,7 @@ Example 4:
// make a copy of the returned const vector - may have to resize
// this in next step
std::vector<int64_t> pads_data;
if (pads_initializer->has_raw_data())
if (utils::HasRawData(*pads_initializer))
return;
else
pads_data.insert(
@ -1547,7 +1548,7 @@ Example 4:
for (size_t i = 0; static_cast<int64_t>(i) < input_rank; ++i) {
const auto& input_dim = input_shape.dim(static_cast<int>(i));
auto* output_dim = output_shape->add_dim();
if (input_dim.has_dim_value()) {
if (utils::HasDimValue(input_dim)) {
output_dim->set_dim_value(
input_dim.dim_value() + pads_data[i] + pads_data[i + input_rank]);
} else if (pads_data[i] + pads_data[i + input_rank] == 0) {

View file

@ -3,6 +3,7 @@
#include "range_schema_defs.h"
#include "core/framework/tensorprotoutils.h"
#include "core/graph/constants.h"
#include "core/graph/op.h"
#include <cmath>
@ -57,7 +58,7 @@ template <typename T>
static T GetFirstElement(const TensorProto* shapeInitializer) {
if (shapeInitializer == nullptr) return T{1};
if (shapeInitializer->has_raw_data()) {
if (utils::HasRawData(*shapeInitializer)) {
const std::string& bytes = shapeInitializer->raw_data();
return *reinterpret_cast<const T*>(bytes.c_str());
}

View file

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "core/framework/tensorprotoutils.h"
#include "core/graph/function_impl.h"
#include "core/graph/graph_viewer.h"
#include "core/graph/model.h"
@ -56,7 +57,7 @@ void IOTypeConstraintHelper(const ONNX_NAMESPACE::FunctionProto* onnx_func_proto
// type attribute, we add its referenced attribute
// into the op's schema
for (auto& attr : node.attribute()) {
if (attr.has_ref_attr_name() && attr.has_type())
if (!attr.ref_attr_name().empty() && utils::HasType(attr))
attribute_type_map[attr.ref_attr_name()] = attr.type();
}
}
@ -230,7 +231,7 @@ FunctionImpl::FunctionImpl(const onnxruntime::Graph& graph,
std::vector<onnxruntime::NodeArg*> inputs;
std::vector<onnxruntime::NodeArg*> outputs;
std::string uniq_identifier = node.name();
if (!node.has_name()) {
if (!utils::HasName(node)) {
std::stringstream ss;
ss << static_cast<const void*>(&node);
uniq_identifier = ss.str();
@ -273,7 +274,7 @@ FunctionImpl::FunctionImpl(const onnxruntime::Graph& graph,
onnxruntime::NodeAttributes new_attr_map;
for (auto& attr : node.attribute()) {
if (attr.has_ref_attr_name()) {
if (!attr.ref_attr_name().empty()) {
auto entry = attr_map.find(attr.ref_attr_name());
if (entry != attr_map.cend()) {
new_attr_map[attr.name()] = entry->second;

View file

@ -12,6 +12,7 @@
#include <stack>
#include "gsl/pointers"
#include "core/framework/tensorprotoutils.h"
#include "core/graph/function.h"
#include "core/graph/function_impl.h"
#include "core/graph/graph_viewer.h"
@ -54,15 +55,15 @@ static bool GraphLoadedFromModelFile(const GraphProto* graph_proto) {
// there are some known invalid usages of dim_param and dim_value. remove them from the TypeProto so that
// they don't affect shape inferencing or the allocation planner
static void RemoveInvalidValues(ONNX_NAMESPACE::TypeProto& type) {
if (type.has_tensor_type() && type.tensor_type().has_shape()) {
if (utils::HasTensorType(type) && utils::HasShape(type.tensor_type())) {
auto* shape = type.mutable_tensor_type()->mutable_shape();
for (int i = 0, end = shape->dim_size(); i < end; ++i) {
auto& dim = *shape->mutable_dim(i);
if (dim.has_dim_param()) {
if (utils::HasDimParam(dim)) {
if (dim.dim_param().empty()) {
dim.clear_dim_param();
}
} else if (dim.has_dim_value()) {
} else if (utils::HasDimValue(dim)) {
if (dim.dim_value() < 0) {
dim.clear_dim_value();
}
@ -93,7 +94,7 @@ DataType NodeArg::Type() const noexcept {
}
const TypeProto* NodeArg::TypeAsProto() const noexcept {
if (node_arg_info_.has_type())
if (utils::HasType(node_arg_info_))
return &node_arg_info_.type();
return nullptr;
@ -105,13 +106,13 @@ const TensorShapeProto* NodeArg::Shape() const {
const auto typeCase = type->value_case();
switch (typeCase) {
case TypeProto::kTensorType: {
if (type->tensor_type().has_shape()) {
if (utils::HasShape(type->tensor_type())) {
return &(type->tensor_type().shape());
}
return nullptr;
}
case TypeProto::kSparseTensorType: {
if (type->sparse_tensor_type().has_shape()) {
if (utils::HasShape(type->sparse_tensor_type())) {
return &(type->sparse_tensor_type().shape());
}
return nullptr;
@ -126,9 +127,6 @@ const TensorShapeProto* NodeArg::Shape() const {
}
void NodeArg::SetShape(const TensorShapeProto& shape) {
if (!node_arg_info_.has_type()) {
return;
}
const auto type_case = node_arg_info_.type().value_case();
switch (type_case) {
@ -148,7 +146,7 @@ void NodeArg::SetShape(const TensorShapeProto& shape) {
}
common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& input_type) {
if (!node_arg_info_.has_type()) {
if (!utils::HasType(node_arg_info_)) {
*node_arg_info_.mutable_type() = input_type;
type_ = DataTypeUtils::ToType(node_arg_info_.type());
return Status::OK();
@ -173,9 +171,9 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu
static_cast<TensorProto_DataType>(input_tensor_elem_type), " != ",
static_cast<TensorProto_DataType>(current_tensor_elem_type));
if (input_tensor_type.has_shape()) {
if (utils::HasShape(input_tensor_type)) {
auto& current_tensor_type = *current_type.mutable_tensor_type();
if (current_tensor_type.has_shape()) {
if (utils::HasShape(current_tensor_type)) {
ORT_RETURN_IF_ERROR(MergeShapeInfo(Name(), input_tensor_type, current_tensor_type));
} else {
current_tensor_type = input_tensor_type;
@ -193,9 +191,9 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu
static_cast<TensorProto_DataType>(input_tensor_elem_type), " != ",
static_cast<TensorProto_DataType>(current_tensor_elem_type));
}
if (input_tensor_type.has_shape()) {
if (utils::HasShape(input_tensor_type)) {
auto& current_tensor_type = *current_type.mutable_sparse_tensor_type();
if (current_tensor_type.has_shape()) {
if (utils::HasShape(current_tensor_type)) {
// TODO: Check if we need to merge shape here
// if so we'd need to provide merging routine ONNX
// mergeInShapeInfo(input_tensor_type, current_tensor_type);
@ -217,7 +215,7 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu
common::Status NodeArg::UpdateTypeAndShape(const NodeArg& node_arg) {
auto status = Status::OK();
if (node_arg.node_arg_info_.has_type())
if (utils::HasType(node_arg.node_arg_info_))
status = UpdateTypeAndShape(node_arg.node_arg_info_.type());
return status;
@ -392,7 +390,7 @@ void Node::Init(const std::string& name,
attributes_ = *attributes;
for (auto& name_to_attr : attributes_) {
if (name_to_attr.second.has_g()) {
if (utils::HasGraph(name_to_attr.second)) {
CreateSubgraph(name_to_attr.first);
}
}
@ -416,7 +414,7 @@ Node::Relationships& Node::MutableRelationships() noexcept {
void Node::CreateSubgraph(const std::string& attr_name) {
auto attr = attributes_.find(attr_name);
if (attr != attributes_.cend() && attr->second.has_g()) {
if (attr != attributes_.cend() && utils::HasGraph(attr->second)) {
GraphProto& mutable_graph = *attr->second.mutable_g();
std::unique_ptr<Graph> subgraph{new Graph(*graph_, mutable_graph)};
attr_to_subgraph_map_.insert({std::string{attr_name}, gsl::not_null<Graph*>{subgraph.get()}});
@ -685,7 +683,7 @@ Graph::Graph(GraphProto* graph_proto, const std::unordered_map<std::string, int>
// type/shape information will be assigned to each node arg when going
// thru all nodes later.
for (auto& graph_input : graph_proto_->input()) {
if (graph_input.has_name() && graph_input.has_type()) {
if (utils::HasName(graph_input) && utils::HasType(graph_input)) {
name_to_type_map[graph_input.name()] = graph_input.type();
// always create a NodeArg for graph input in case its from an initializer
GetOrCreateNodeArg(graph_input.name(), &graph_input.type());
@ -693,7 +691,7 @@ Graph::Graph(GraphProto* graph_proto, const std::unordered_map<std::string, int>
}
for (auto& graph_output : graph_proto_->output()) {
if (graph_output.has_name() && graph_output.has_type()) {
if (utils::HasName(graph_output) && utils::HasType(graph_output)) {
auto& name = graph_output.name();
name_to_type_map[name] = graph_output.type();
// always create NodeArg for graph output, in case it's from initializer
@ -702,7 +700,7 @@ Graph::Graph(GraphProto* graph_proto, const std::unordered_map<std::string, int>
}
for (auto& node_arg : graph_proto_->value_info()) {
if (node_arg.has_name() && node_arg.has_type()) {
if (utils::HasName(node_arg) && utils::HasType(node_arg)) {
name_to_type_map[node_arg.name()] = node_arg.type();
}
}
@ -1181,21 +1179,20 @@ bool FullyDefinedType(const TypeProto& type_proto) {
switch (type_proto.value_case()) {
case TypeProto::kTensorType: {
auto& tensor_type = type_proto.tensor_type();
return tensor_type.has_elem_type() && (tensor_type.elem_type() != TensorProto::UNDEFINED);
return utils::HasElemType(tensor_type);
}
case TypeProto::kSparseTensorType: {
auto& tensor_type = type_proto.sparse_tensor_type();
return tensor_type.has_elem_type() && (tensor_type.elem_type() != TensorProto::UNDEFINED);
return utils::HasElemType(tensor_type);
}
case TypeProto::kSequenceType: {
auto& seq_type = type_proto.sequence_type();
return seq_type.has_elem_type() && FullyDefinedType(seq_type.elem_type());
return utils::HasElemType(seq_type) && FullyDefinedType(seq_type.elem_type());
}
case TypeProto::kMapType: {
auto& map_type = type_proto.map_type();
return map_type.has_key_type() &&
(map_type.key_type() != TensorProto::UNDEFINED) &&
map_type.has_value_type() &&
return utils::HasKeyType(map_type) &&
utils::HasValueType(map_type) &&
FullyDefinedType(map_type.value_type());
}
case TypeProto::kOpaqueType:
@ -1567,9 +1564,9 @@ Status Graph::InferAndVerifyTypeMatch(Node& node, const OpSchema& op) {
output_def->SetType(inferred_type);
// Update output-shape if it was inferred:
if (onnx_inferred_type.has_tensor_type()) {
if (utils::HasTensorType(onnx_inferred_type)) {
auto& tensor_type = onnx_inferred_type.tensor_type();
if (tensor_type.has_shape()) {
if (utils::HasShape(tensor_type)) {
if (output_def->Shape() == nullptr) {
output_def->SetShape(tensor_type.shape());
} else {
@ -1639,7 +1636,7 @@ common::Status Graph::TypeCheckInputsAndInitializers() {
"Type Error: Shape of initializer " + name + " does not match its type.");
for (int i = 0; i < p_existing_shape->dim_size(); ++i) {
auto& d = p_existing_shape->dim(i);
if (d.has_dim_value() && (d.dim_value() != tensor_proto->dims(i)))
if (utils::HasDimValue(d) && (d.dim_value() != tensor_proto->dims(i)))
return Status(ONNXRUNTIME, FAIL,
"Type Error: Shape of initializer " + initializer_pair.first + " does not match its type.");
}
@ -1729,7 +1726,7 @@ Status Graph::VerifyNodeAndOpMatch() {
if (node_attributes.end() == node_attr_iter) {
// The attribute was not specified in the node.
if (!attr_def.second.required) {
if (attr_def.second.default_value.has_name()) {
if (utils::HasName(attr_def.second.default_value)) {
// Set default value to the node attributes.
node.AddAttribute(attr_def.first, attr_def.second.default_value);
}

View file

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "core/framework/tensorprotoutils.h"
#include "core/graph/model.h"
#include <memory>
#include "core/common/logging/logging.h"
@ -81,7 +82,7 @@ Model::Model(std::unique_ptr<ModelProto> model_proto, const IOnnxRuntimeOpSchema
throw std::invalid_argument("ModelProto was null.");
}
if (!model_proto->has_graph()) {
if (!utils::HasGraph(*model_proto)) {
throw std::invalid_argument("ModelProto does not have a graph.");
}
@ -150,7 +151,7 @@ Model::Model(std::unique_ptr<ModelProto> model_proto, const IOnnxRuntimeOpSchema
}
Version Model::IrVersion() const {
if (model_proto_->has_ir_version()) {
if (utils::HasIrVersion(*model_proto_)) {
return model_proto_->ir_version();
}
return kNoVersion;
@ -181,7 +182,7 @@ void Model::SetDomain(const std::string& domain) {
}
Version Model::ModelVersion() const {
if (model_proto_->has_model_version()) {
if (utils::HasModelVersion(*model_proto_)) {
return model_proto_->model_version();
}
return kNoVersion;
@ -239,7 +240,7 @@ Status Model::Load(std::istream& model_istream, ModelProto* p_model_proto) {
Status Model::Load(const ModelProto& model_proto, std::shared_ptr<Model>& model, const IOnnxRuntimeOpSchemaRegistryList* local_registries) {
// we expect a graph to be present
if (!model_proto.has_graph()) {
if (!utils::HasGraph(model_proto)) {
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "No graph was found in the protobuf.");
}
@ -258,7 +259,7 @@ Status Model::Load(const ModelProto& model_proto, std::shared_ptr<Model>& model,
Status Model::Load(std::unique_ptr<ModelProto> p_model_proto, std::shared_ptr<Model>& model, const IOnnxRuntimeOpSchemaRegistryList* local_registries) {
// we expect a graph to be present
if (!p_model_proto->has_graph()) {
if (!utils::HasGraph(*p_model_proto)) {
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "No graph was found in the protobuf.");
}

View file

@ -1,4 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "language_interop_ops.h"
#include "core/framework/tensorprotoutils.h"
#include "core/platform/env.h"
#include "core/session/inference_session.h"
#include "pyop/pyop.h"
@ -7,47 +11,45 @@
namespace onnxruntime {
void InterOpDomainDeleter(OrtCustomOpDomain* domain) {
if (nullptr != domain) {
for (auto op: domain->custom_ops_) {
delete op;
}
delete domain;
if (nullptr != domain) {
for (auto op : domain->custom_ops_) {
delete op;
}
delete domain;
}
}
void LoadInterOp(const std::basic_string<ORTCHAR_T>& model_uri, InterOpDomains& domains, const InterOpLogFunc& log_func)
{
int fd;
ORT_ENFORCE(Env::Default().FileOpenRd(model_uri, fd).IsOK(), "Failed to read model file");
google::protobuf::io::FileInputStream f(fd);
f.SetCloseOnDelete(true);
ONNX_NAMESPACE::ModelProto model_proto;
ORT_ENFORCE(model_proto.ParseFromZeroCopyStream(&f), "Failed to parse model proto");
LoadInterOp(model_proto, domains, log_func);
void LoadInterOp(const std::basic_string<ORTCHAR_T>& model_uri, InterOpDomains& domains, const InterOpLogFunc& log_func) {
int fd;
ORT_ENFORCE(Env::Default().FileOpenRd(model_uri, fd).IsOK(), "Failed to read model file");
google::protobuf::io::FileInputStream f(fd);
f.SetCloseOnDelete(true);
ONNX_NAMESPACE::ModelProto model_proto;
ORT_ENFORCE(model_proto.ParseFromZeroCopyStream(&f), "Failed to parse model proto");
LoadInterOp(model_proto, domains, log_func);
}
void LoadInterOp(const ONNX_NAMESPACE::ModelProto& model_proto, InterOpDomains& domains, const InterOpLogFunc& log_func)
{
LoadInterOp(model_proto.graph(), domains, log_func);
void LoadInterOp(const ONNX_NAMESPACE::ModelProto& model_proto, InterOpDomains& domains, const InterOpLogFunc& log_func) {
LoadInterOp(model_proto.graph(), domains, log_func);
}
void LoadInterOp(const ONNX_NAMESPACE::GraphProto& graph_proto, InterOpDomains& domains, const InterOpLogFunc& log_func) {
for (int i = 0; i < graph_proto.node_size(); ++i) {
const auto& node_proto = graph_proto.node(i);
if (node_proto.op_type() == "PyOp") {
OrtCustomOpDomain* pyop_domain = nullptr;
ORT_THROW_ON_ERROR(OrtCreateCustomOpDomain(node_proto.domain().c_str(), &pyop_domain));
ORT_THROW_ON_ERROR(OrtCustomOpDomain_Add(pyop_domain, LoadPyOp(node_proto, log_func)));
auto ort_domain = std::unique_ptr<OrtCustomOpDomain,decltype(&InterOpDomainDeleter)>(pyop_domain, &InterOpDomainDeleter);
domains.push_back(std::move(ort_domain));
} else {
for (int j = 0; j < node_proto.attribute_size(); ++j) {
const auto& attr = node_proto.attribute(j);
if (attr.has_g()) {
LoadInterOp(attr.g(), domains, log_func); //load pyop in subgraph
}
}//for
}//else
}//for
}
for (int i = 0; i < graph_proto.node_size(); ++i) {
const auto& node_proto = graph_proto.node(i);
if (node_proto.op_type() == "PyOp") {
OrtCustomOpDomain* pyop_domain = nullptr;
ORT_THROW_ON_ERROR(OrtCreateCustomOpDomain(node_proto.domain().c_str(), &pyop_domain));
ORT_THROW_ON_ERROR(OrtCustomOpDomain_Add(pyop_domain, LoadPyOp(node_proto, log_func)));
auto ort_domain = std::unique_ptr<OrtCustomOpDomain, decltype(&InterOpDomainDeleter)>(pyop_domain, &InterOpDomainDeleter);
domains.push_back(std::move(ort_domain));
} else {
for (int j = 0; j < node_proto.attribute_size(); ++j) {
const auto& attr = node_proto.attribute(j);
if (utils::HasGraph(attr)) {
LoadInterOp(attr.g(), domains, log_func); //load pyop in subgraph
}
} //for
} //else
} //for
}
} // namespace onnxruntime

View file

@ -1,139 +1,137 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pyop.h"
#ifdef _WIN32
#define LIB_PYOP "onnxruntime_pywrapper.dll"
#define LOAD_PYOP_LIB(n,v,m) ORT_ENFORCE((v=LoadLibraryA(n))!=nullptr,m)
#define LOAD_PYOP_LIB(n, v, m) ORT_ENFORCE((v = LoadLibraryA(n)) != nullptr, m)
#else
#ifdef __APPLE__
#define LIB_PYOP "./libonnxruntime_pywrapper.dylib"
#else
#define LIB_PYOP "./libonnxruntime_pywrapper.so"
#endif
#define LOAD_PYOP_LIB(n,v,m) ORT_ENFORCE((v=dlopen(n,RTLD_NOW|RTLD_GLOBAL))!=nullptr,m)
#define LOAD_PYOP_LIB(n, v, m) ORT_ENFORCE((v = dlopen(n, RTLD_NOW | RTLD_GLOBAL)) != nullptr, m)
#include "dlfcn.h"
#endif
#include "core/framework/tensorprotoutils.h"
#include "core/platform/env.h"
#define LOAD_PYOP_SYM(n,v,m) ORT_ENFORCE(Env::Default().GetSymbolFromLibrary(handle_,n,reinterpret_cast<void**>(&v))==Status::OK(),m)
// #define LOAD_PYOP_SYM(n, v, m) ORT_ENFORCE(Env::Default().GetSymbolFromLibrary(handle_, n, reinterpret_cast<void**>(&v)) == Status::OK(), m)
namespace onnxruntime {
const PyOpLibProxy& PyOpLibProxy::GetInstance() {
static PyOpLibProxy proxy;
return proxy;
static PyOpLibProxy proxy;
return proxy;
}
PyOpLibProxy:: PyOpLibProxy() {
std::string err;
LOAD_PYOP_LIB(LIB_PYOP, handle_, "Failed to load pyop library");
LOAD_PYOP_SYM("Initialize", initialize_, "Failed to import function: Initialize");
LOAD_PYOP_SYM("NewInstance", new_instance_, "Failed to import function: NewInstance");
LOAD_PYOP_SYM("InvokePythonFunc", invoke_python_func_, "Failed to import function: InvokePythonFunc");
LOAD_PYOP_SYM("ReleaseInstance", release_instance_, "Failed to import function: ReleaseInstance");
LOAD_PYOP_SYM("GetLastErrorMessage", get_last_error_message_, "Failed to import function: GetLastErrorMessage");
ORT_ENFORCE (initialize_(), get_last_error_message_(err));
PyOpLibProxy::PyOpLibProxy() {
std::string err;
LOAD_PYOP_LIB(LIB_PYOP, handle_, "Failed to load pyop library");
LOAD_PYOP_SYM("Initialize", initialize_, "Failed to import function: Initialize");
LOAD_PYOP_SYM("NewInstance", new_instance_, "Failed to import function: NewInstance");
LOAD_PYOP_SYM("InvokePythonFunc", invoke_python_func_, "Failed to import function: InvokePythonFunc");
LOAD_PYOP_SYM("ReleaseInstance", release_instance_, "Failed to import function: ReleaseInstance");
LOAD_PYOP_SYM("GetLastErrorMessage", get_last_error_message_, "Failed to import function: GetLastErrorMessage");
ORT_ENFORCE(initialize_(), get_last_error_message_(err));
}
PyOpLibProxy::~PyOpLibProxy() {
Env::Default().UnloadDynamicLibrary(handle_);
Env::Default().UnloadDynamicLibrary(handle_);
}
PyCustomKernel::PyCustomKernel(Ort::CustomOpApi ort,
const OnnxAttrs& attrs,
PyCustomKernel::PyCustomKernel(Ort::CustomOpApi ort,
const OnnxAttrs& attrs,
const std::string& module,
const std::string& class_name,
const std::string& compute,
PyOpLogFunc logging_func):
ort_(ort), attrs_(attrs), module_(module), class_name_(class_name),
compute_(compute), logging_func_(logging_func) {
std::string err;
instance_ = PyOpLibProxy::GetInstance().new_instance_(module.c_str(), class_name_.c_str(), attrs_);
ORT_ENFORCE(nullptr != instance_, PyOpLibProxy::GetInstance().get_last_error_message_(err));
PyOpLogFunc logging_func) : ort_(ort), attrs_(attrs), module_(module), class_name_(class_name), compute_(compute), logging_func_(logging_func) {
std::string err;
instance_ = PyOpLibProxy::GetInstance().new_instance_(module.c_str(), class_name_.c_str(), attrs_);
ORT_ENFORCE(nullptr != instance_, PyOpLibProxy::GetInstance().get_last_error_message_(err));
}
PyCustomKernel::~PyCustomKernel() {
if (nullptr != instance_) {
PyOpLibProxy::GetInstance().release_instance_(instance_);
instance_ = nullptr;
}
if (nullptr != instance_) {
PyOpLibProxy::GetInstance().release_instance_(instance_);
instance_ = nullptr;
}
}
// Do nothing since Custom Op does not trigger shape inference
void PyCustomKernel::GetOutputShape(OrtKernelContext*, size_t, OrtTensorTypeAndShapeInfo*) {}
void PyCustomKernel::Compute(OrtKernelContext* context) {
ORT_ENFORCE(nullptr != context);
auto inputs_count = (size_t) reinterpret_cast<onnxruntime::OpKernelContextInternal*>(context)->InputCount();
std::vector<const void*> inputs;
std::vector<std::unique_ptr<char[]>> outputs;
std::vector<int32_t> inputs_type, outputs_elem_size;
std::vector<std::vector<int64_t>> inputs_dim, outputs_dim;
ORT_ENFORCE (nullptr != context);
auto inputs_count = (size_t)reinterpret_cast<onnxruntime::OpKernelContextInternal*>(context)->InputCount();
std::vector<const void*> inputs;
std::vector<std::unique_ptr<char[]>> outputs;
std::vector<int32_t> inputs_type, outputs_elem_size;
std::vector<std::vector<int64_t>> inputs_dim, outputs_dim;
for (size_t i = 0; i < inputs_count; ++i) {
auto ort_value = ort_.KernelContext_GetInput(context, i);
inputs.push_back(const_cast<MLValue*>(ort_value)->Get<Tensor>().DataRaw());
inputs_type.push_back(GetType(ort_value));
inputs_dim.push_back(const_cast<MLValue*>(ort_value)->Get<Tensor>().Shape().GetDims());
}
for (size_t i = 0; i < inputs_count; ++i) {
auto ort_value = ort_.KernelContext_GetInput(context, i);
inputs.push_back(const_cast<MLValue*>(ort_value)->Get<Tensor>().DataRaw());
inputs_type.push_back(GetType(ort_value));
inputs_dim.push_back(const_cast<MLValue*>(ort_value)->Get<Tensor>().Shape().GetDims());
}
std::string err;
ORT_ENFORCE(PyOpLibProxy::GetInstance().invoke_python_func_(instance_, compute_.c_str(), inputs, inputs_type,
inputs_dim, outputs, outputs_elem_size,
outputs_dim, logging_func_),
PyOpLibProxy::GetInstance().get_last_error_message_(err)); //ORT_ENFORCE
std::string err;
ORT_ENFORCE(PyOpLibProxy::GetInstance().invoke_python_func_(instance_, compute_.c_str(), inputs, inputs_type,
inputs_dim, outputs, outputs_elem_size,
outputs_dim, logging_func_),
PyOpLibProxy::GetInstance().get_last_error_message_(err));//ORT_ENFORCE
for (size_t i = 0; i < outputs.size(); ++i) {
auto ort_output = ort_.KernelContext_GetOutput(context, i, outputs_dim[i].data(), outputs_dim[i].size());
auto output_mem_addr = ort_.GetTensorMutableData<char>(ort_output);
auto output_len = std::accumulate(begin(outputs_dim[i]), end(outputs_dim[i]), static_cast<int64_t>(outputs_elem_size[i]), std::multiplies<int64_t>());
memcpy(output_mem_addr, outputs[i].get(), output_len);
}
for (size_t i = 0; i < outputs.size(); ++i) {
auto ort_output = ort_.KernelContext_GetOutput(context, i, outputs_dim[i].data(), outputs_dim[i].size());
auto output_mem_addr = ort_.GetTensorMutableData<char>(ort_output);
auto output_len = std::accumulate(begin(outputs_dim[i]), end(outputs_dim[i]), static_cast<int64_t>(outputs_elem_size[i]), std::multiplies<int64_t>());
memcpy(output_mem_addr, outputs[i].get(), output_len);
}
}
int32_t PyCustomKernel::GetType(const OrtValue* input) const {
int32_t numpy_type;
ORT_ENFORCE (nullptr != input);
ORT_ENFORCE(const_cast<MLValue*>(input)->IsTensor(), "input must be a tensor");
auto data_type = const_cast<MLValue*>(input)->Get<Tensor>().DataType();
if (data_type == DataTypeImpl::GetType<bool>()) {
numpy_type = 0;
} else if (data_type == DataTypeImpl::GetType<int8_t>()) {
numpy_type = 1;
} else if (data_type == DataTypeImpl::GetType<uint8_t>()) {
numpy_type = 2;
} else if (data_type == DataTypeImpl::GetType<int16_t>()) {
numpy_type = 3;
} else if (data_type == DataTypeImpl::GetType<uint16_t>()) {
numpy_type = 4;
} else if (data_type == DataTypeImpl::GetType<int32_t>()) {
numpy_type = 5;
} else if (data_type == DataTypeImpl::GetType<uint32_t>()) {
numpy_type = 6;
} else if (data_type == DataTypeImpl::GetType<int64_t>()) {
numpy_type = 9;
} else if (data_type == DataTypeImpl::GetType<uint64_t>()) {
numpy_type = 10;
} else if (data_type == DataTypeImpl::GetType<float>()) {
numpy_type = 11;
} else if (data_type == DataTypeImpl::GetType<double>()) {
numpy_type = 12;
} else ORT_ENFORCE(false, "Input type not supported");
return numpy_type;
int32_t numpy_type;
ORT_ENFORCE(nullptr != input);
ORT_ENFORCE(const_cast<MLValue*>(input)->IsTensor(), "input must be a tensor");
auto data_type = const_cast<MLValue*>(input)->Get<Tensor>().DataType();
if (data_type == DataTypeImpl::GetType<bool>()) {
numpy_type = 0;
} else if (data_type == DataTypeImpl::GetType<int8_t>()) {
numpy_type = 1;
} else if (data_type == DataTypeImpl::GetType<uint8_t>()) {
numpy_type = 2;
} else if (data_type == DataTypeImpl::GetType<int16_t>()) {
numpy_type = 3;
} else if (data_type == DataTypeImpl::GetType<uint16_t>()) {
numpy_type = 4;
} else if (data_type == DataTypeImpl::GetType<int32_t>()) {
numpy_type = 5;
} else if (data_type == DataTypeImpl::GetType<uint32_t>()) {
numpy_type = 6;
} else if (data_type == DataTypeImpl::GetType<int64_t>()) {
numpy_type = 9;
} else if (data_type == DataTypeImpl::GetType<uint64_t>()) {
numpy_type = 10;
} else if (data_type == DataTypeImpl::GetType<float>()) {
numpy_type = 11;
} else if (data_type == DataTypeImpl::GetType<double>()) {
numpy_type = 12;
} else
ORT_ENFORCE(false, "Input type not supported");
return numpy_type;
}
PyCustomOp::PyCustomOp(const OnnxAttrs& attrs,
const OnnxTypes& inputs_type,
const OnnxTypes& outputs_type,
const std::string& module,
const std::string& class_name,
const std::string& compute,
PyOpLogFunc logging_func):
attrs_(attrs), inputs_type_(inputs_type),
outputs_type_(outputs_type), module_(module),
class_name_(class_name), compute_(compute),
logging_func_(logging_func) { OrtCustomOp::version = ORT_API_VERSION; }
PyCustomOp::PyCustomOp(const OnnxAttrs& attrs,
const OnnxTypes& inputs_type,
const OnnxTypes& outputs_type,
const std::string& module,
const std::string& class_name,
const std::string& compute,
PyOpLogFunc logging_func) : attrs_(attrs), inputs_type_(inputs_type), outputs_type_(outputs_type), module_(module), class_name_(class_name), compute_(compute), logging_func_(logging_func) { OrtCustomOp::version = ORT_API_VERSION; }
void* PyCustomOp::CreateKernel(Ort::CustomOpApi api, const OrtKernelInfo*) {
return new PyCustomKernel(api, attrs_, module_, class_name_, compute_, logging_func_);
return new PyCustomKernel(api, attrs_, module_, class_name_, compute_, logging_func_);
}
const char* PyCustomOp::GetName() const { return "PyOp"; }
@ -144,35 +142,37 @@ ONNXTensorElementDataType PyCustomOp::GetInputType(size_t index) const { return
size_t PyCustomOp::GetOutputTypeCount() const { return outputs_type_.size(); }
ONNXTensorElementDataType PyCustomOp::GetOutputType(size_t index) const { return outputs_type_[index]; }
PyCustomOp* LoadPyOp(const ONNX_NAMESPACE::NodeProto& node_proto, PyOpLogFunc log_func)
{
OnnxAttrs onnx_attrs;
OnnxTypes input_types, output_types;
std::string module, class_name, compute = "compute";
for (int j = 0; j < node_proto.attribute_size(); ++j) {
const auto& attr = node_proto.attribute(j);
if (attr.has_s()) {
if (attr.name() == "module") module = attr.s();
else if (attr.name() == "class_name") class_name = attr.s();
else if (attr.name() == "compute") compute = attr.s();
else onnx_attrs[attr.name()] = attr.s();
} else if (attr.ints_size() > 0) {
if (attr.name() == "input_types") {
for (int k = 0; k < attr.ints_size(); ++k) {
input_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
}
} else if (attr.name() == "output_types") {
for (int k = 0; k < attr.ints_size(); ++k) {
output_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
}
}
}
}//for
ORT_ENFORCE (module != "", "PyOp module not specified");
ORT_ENFORCE (class_name != "", "PyOp class name not specified");
ORT_ENFORCE (!input_types.empty(), "PyOp node inputs not specified");
ORT_ENFORCE (!output_types.empty(), "PyOp node outputs not specified");
return new PyCustomOp(onnx_attrs, input_types, output_types, module, class_name, compute, log_func);
PyCustomOp* LoadPyOp(const ONNX_NAMESPACE::NodeProto& node_proto, PyOpLogFunc log_func) {
OnnxAttrs onnx_attrs;
OnnxTypes input_types, output_types;
std::string module, class_name, compute = "compute";
for (int j = 0; j < node_proto.attribute_size(); ++j) {
const auto& attr = node_proto.attribute(j);
if (utils::HasString(attr)) {
if (attr.name() == "module")
module = attr.s();
else if (attr.name() == "class_name")
class_name = attr.s();
else if (attr.name() == "compute")
compute = attr.s();
else
onnx_attrs[attr.name()] = attr.s();
} else if (attr.ints_size() > 0) {
if (attr.name() == "input_types") {
for (int k = 0; k < attr.ints_size(); ++k) {
input_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
}
} else if (attr.name() == "output_types") {
for (int k = 0; k < attr.ints_size(); ++k) {
output_types.push_back(static_cast<ONNXTensorElementDataType>(attr.ints(k)));
}
}
}
} //for
ORT_ENFORCE(module != "", "PyOp module not specified");
ORT_ENFORCE(class_name != "", "PyOp class name not specified");
ORT_ENFORCE(!input_types.empty(), "PyOp node inputs not specified");
ORT_ENFORCE(!output_types.empty(), "PyOp node outputs not specified");
return new PyCustomOp(onnx_attrs, input_types, output_types, module, class_name, compute, log_func);
}
}
} // namespace onnxruntime

View file

@ -8,6 +8,7 @@
#include <cmath>
#include "core/common/common.h"
#include "core/framework/tensorprotoutils.h"
#include "core/graph/onnx_protobuf.h"
#include "core/util/math.h"
@ -52,7 +53,7 @@ class Initializer final {
Initializer(const ONNX_NAMESPACE::TensorProto* tensor_proto) : size_(0) {
data_type_ = tensor_proto->data_type();
if (tensor_proto->has_name()) {
if (utils::HasName(*tensor_proto)) {
name_ = tensor_proto->name();
}
dims_.reserve(tensor_proto->dims_size());
@ -62,7 +63,7 @@ class Initializer final {
size_ = std::accumulate(dims_.begin(), dims_.end(), static_cast<int64_t>(1), std::multiplies<int64_t>{});
if (tensor_proto->has_raw_data()) {
if (utils::HasRawData(*tensor_proto)) {
raw_data_ = tensor_proto->raw_data();
} else {
switch (data_type_) {

View file

@ -236,7 +236,7 @@ void NchwcTransformerImpl::ConvPoolShapeInference(const Node& node,
auto* auto_pad_attr = graph_utils::GetNodeAttribute(node, "auto_pad");
bool auto_pad_same_shape = false;
if (auto_pad_attr != nullptr && auto_pad_attr->has_s()) {
if (auto_pad_attr != nullptr && utils::HasString(*auto_pad_attr)) {
auto& auto_pad = auto_pad_attr->s();
if (auto_pad != "NOTSET") {
if (auto_pad == "SAME_UPPER" || auto_pad == "SAME_LOWER") {
@ -303,7 +303,7 @@ void NchwcTransformerImpl::TransformConv(Node& node) {
int64_t group_count;
auto* group_attr = graph_utils::GetNodeAttribute(node, "group");
if (group_attr != nullptr && group_attr->has_i()) {
if (group_attr != nullptr && utils::HasInt(*group_attr)) {
group_count = group_attr->i();
} else {
group_count = 1;
@ -471,7 +471,7 @@ void NchwcTransformerImpl::TransformPool(Node& node) {
return;
}
auto& channels_dim = input_shape->dim(1);
if (!channels_dim.has_dim_value()) {
if (!utils::HasDimValue(channels_dim)) {
return;
}
const int64_t channels = channels_dim.dim_value();
@ -539,8 +539,8 @@ void NchwcTransformerImpl::TransformAdd(Node& node) {
}
auto& nchwc_input_0_dim = nchwc_input_0_shape->dim(i);
auto& nchwc_input_n_dim = nchwc_input_n_shape->dim(i);
if (!nchwc_input_0_dim.has_dim_value() ||
!nchwc_input_n_dim.has_dim_value() ||
if (!utils::HasDimValue(nchwc_input_0_dim) ||
!utils::HasDimValue(nchwc_input_n_dim) ||
(nchwc_input_0_dim.dim_value() <= 0) ||
(nchwc_input_0_dim.dim_value() != nchwc_input_n_dim.dim_value())) {
return;
@ -594,7 +594,7 @@ void NchwcTransformerImpl::TransformConcat(Node& node) {
// Verify that this is a concatenation along the channel axis.
auto* axis_attr = graph_utils::GetNodeAttribute(node, "axis");
if (axis_attr == nullptr || !axis_attr->has_i() || axis_attr->i() != 1) {
if (axis_attr == nullptr || !utils::HasInt(*axis_attr) || axis_attr->i() != 1) {
return;
}

View file

@ -68,7 +68,7 @@ bool ShapeToInitializer::SatisfyCondition(const Graph& graph, const Node& node)
for (int i = 0, num_dims = input_shape->dim_size(); i < num_dims; i++) {
const auto& input_dim = input_shape->dim(i);
if (!input_dim.has_dim_value() || input_dim.dim_value() < 0) {
if (!utils::HasDimValue(input_dim) || input_dim.dim_value() < 0) {
return false;
}
}

View file

@ -39,11 +39,11 @@ ONNX_CPU_OPERATOR_KERNEL(
void onnxruntime::ConstantOfShapeBase::SetValueFromTensorProto(const ONNX_NAMESPACE::TensorProto& t_proto) {
using namespace utils;
ORT_ENFORCE(t_proto.has_data_type());
ORT_ENFORCE(utils::HasDataType(t_proto));
ORT_ENFORCE(TensorProto::DataType_IsValid(t_proto.data_type()));
const auto tensor_type = static_cast<TensorProto_DataType>(t_proto.data_type());
const void* const raw_data = t_proto.has_raw_data() ? t_proto.raw_data().data() : nullptr;
const size_t raw_data_len = t_proto.has_raw_data() ? t_proto.raw_data().size() : 0;
const void* const raw_data = utils::HasRawData(t_proto) ? t_proto.raw_data().data() : nullptr;
const size_t raw_data_len = utils::HasRawData(t_proto) ? t_proto.raw_data().size() : 0;
switch (tensor_type) {
case TensorProto::BOOL:
FETCH_VALUE_DATA(bool);

View file

@ -14,7 +14,7 @@ bool NodeArgShapeUnknownOnAxis(const NodeArg* def, int64_t axis) {
axis = HandleNegativeAxis(axis, shape->dim_size());
ORT_ENFORCE(axis < shape->dim_size());
auto dim = shape->dim(axis);
return dim.has_dim_param() || (!dim.has_dim_param() && !dim.has_dim_value());
return utils::HasDimParam(dim) || (!utils::HasDimParam(dim) && !utils::HasDimValue(dim));
}
bool HasUnknownShapeOnAxis(const ConstPointerContainer<std::vector<NodeArg*>>& defs, int64_t axis) {

View file

@ -28,9 +28,9 @@ static bool CreateInput(const NodeArg* def,
input = ShapeExpr(rank);
for (int i = 0; i < rank; ++i) {
const auto& dim = def_shape->dim()[i];
if (dim.has_dim_value())
if (utils::HasDimValue(dim))
input[i] = DimExpr(dim.dim_value());
else if (dim.has_dim_param())
else if (utils::HasDimParam(dim))
input[i] = DimExpr(dim.dim_param());
else {
input[i] = DimExpr(NormalizeNodeArgName(def) + "_dim" + std::to_string(i));
@ -56,7 +56,7 @@ static Status CreateOutputs(
if (shape[d] > 0) {
output_shape[d] = DimExpr(shape[d]);
} else {
ORT_RETURN_IF_NOT(shape_proto->dim_size() > d && shape_proto->dim(d).has_dim_param());
ORT_RETURN_IF_NOT(shape_proto->dim_size() > d && utils::HasDimParam(shape_proto->dim(d)));
output_shape[d] = DimExpr(shape_proto->dim(d).dim_param());
}
}

View file

@ -180,7 +180,7 @@ NupharExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_vie
all_shape_defined = false;
} else {
for (const auto& dim : def.Shape()->dim()) {
if (!((dim.has_dim_value() && dim.dim_value() > 0) || dim.has_dim_param()))
if (!((utils::HasDimValue(dim) && dim.dim_value() > 0) || utils::HasDimParam(dim)))
all_shape_defined = false;
}
}

View file

@ -5,6 +5,7 @@
#include "core/codegen/common/common.h"
#include "core/common/logging/logging.h"
#include "core/framework/tensorprotoutils.h"
#include "core/providers/nuphar/common/analysis/subgraph_partition_stats.h"
#include "core/providers/nuphar/common/nuphar_settings.h"
#include "core/providers/nuphar/common/utils.h"
@ -41,10 +42,10 @@ bool GraphPartitioner::IsNodeSupported(const Node& node) const {
node.ForEachDef([&](const NodeArg& def, bool is_input) {
if (is_input == check_input && def.Shape() != nullptr) {
for (const auto& dim : def.Shape()->dim()) {
if (dim.has_dim_param())
if (utils::HasDimParam(dim))
symbolic_dimensions.insert(dim.dim_param());
else
ORT_ENFORCE(dim.has_dim_value() && dim.dim_value() > 0);
ORT_ENFORCE(utils::HasDimValue(dim) && dim.dim_value() > 0);
}
}
});

View file

@ -7,6 +7,7 @@
#define PY_ARRAY_UNIQUE_SYMBOL onnxruntime_python_ARRAY_API
#include <numpy/arrayobject.h>
#include "core/framework/tensorprotoutils.h"
#include "core/graph/graph_viewer.h"
#include "core/common/logging/logging.h"
#include "core/common/logging/severity.h"
@ -581,9 +582,9 @@ including arg name, arg type (contains both type and shape).)pbdoc")
} else {
res << "[";
for (int i = 0; i < shape->dim_size(); ++i) {
if (shape->dim(i).has_dim_value()) {
if (utils::HasDimValue(shape->dim(i))) {
res << shape->dim(i).dim_value();
} else if (shape->dim(i).has_dim_param()) {
} else if (utils::HasDimParam(shape->dim(i))) {
res << "'" << shape->dim(i).dim_param() << "'";
} else {
res << "None";
@ -609,9 +610,9 @@ including arg name, arg type (contains both type and shape).)pbdoc")
arr.resize(shape->dim_size());
for (int i = 0; i < shape->dim_size(); ++i) {
if (shape->dim(i).has_dim_value()) {
if (utils::HasDimValue(shape->dim(i))) {
arr[i] = py::cast(shape->dim(i).dim_value());
} else if (shape->dim(i).has_dim_param()) {
} else if (utils::HasDimParam(shape->dim(i))) {
arr[i] = py::cast(shape->dim(i).dim_param());
} else {
arr[i] = py::none();

View file

@ -284,12 +284,22 @@ bool AreShapesEqual(const std::vector<int64_t>& real_shape, const ::ONNX_NAMESPA
if (len < 0) return false;
if (real_shape.size() != static_cast<size_t>(len)) return false;
for (int i = 0; i != len; ++i) {
if (!expected_shape.dim(i).has_dim_value()) {
// symbolic shape, cannot validate it right now, assume it matches every thing
continue;
const auto& dim = expected_shape.dim(i);
switch (dim.value_case()) {
case ONNX_NAMESPACE::TensorShapeProto::Dimension::kDimValue:
if (dim.dim_value() != real_shape[i]) return false;
break;
case ONNX_NAMESPACE::TensorShapeProto::Dimension::kDimParam:
// symbolic shape, cannot validate it right now, assume it matches every thing
// fall through
case ONNX_NAMESPACE::TensorShapeProto::Dimension::VALUE_NOT_SET:
// Value not set is treated as can not be validated
continue;
break;
// This is for unlikely case when we add new oneof value
default : assert(false);
break;
}
::google::protobuf::int64 d = expected_shape.dim(i).dim_value();
if (d != real_shape[i]) return false;
}
return true;
}