Support disabling support for the optional type in ORT builds (#9745)

This commit is contained in:
Hariharan Seshadri 2021-11-17 19:13:28 -08:00 committed by GitHub
parent 9fb3fac5a0
commit e23892ddbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1548 additions and 1213 deletions

View file

@ -108,6 +108,7 @@ option(onnxruntime_USE_ROCM "Build with AMD GPU support" OFF)
option(onnxruntime_DISABLE_CONTRIB_OPS "Disable contrib ops" OFF)
option(onnxruntime_DISABLE_ML_OPS "Disable traditional ML ops" OFF)
option(onnxruntime_DISABLE_SPARSE_TENSORS "Disable sparse tensors data types" OFF)
option(onnxruntime_DISABLE_OPTIONAL_TYPE "Disable optional type" OFF)
option(onnxruntime_MINIMAL_BUILD "Exclude as much as possible from the build. Support ORT format models. No support for ONNX format models." OFF)
cmake_dependent_option(onnxruntime_DISABLE_RTTI "Disable RTTI" ON "NOT onnxruntime_ENABLE_PYTHON" OFF)
# For now onnxruntime_DISABLE_EXCEPTIONS will only work with onnxruntime_MINIMAL_BUILD, more changes (ONNX, non-CPU EP, ...) are required to run this standalone
@ -817,6 +818,10 @@ if (onnxruntime_DISABLE_SPARSE_TENSORS)
add_compile_definitions(DISABLE_SPARSE_TENSORS)
endif()
if (onnxruntime_DISABLE_OPTIONAL_TYPE)
add_compile_definitions(DISABLE_OPTIONAL_TYPE)
endif()
if (onnxruntime_USE_CUDA AND "${onnxruntime_CUDNN_HOME}" STREQUAL "")
message(FATAL_ERROR "onnxruntime_CUDNN_HOME required for onnxruntime_USE_CUDA")
endif()

View file

@ -60,7 +60,9 @@ class SparseTensorTypeBase;
#endif
class SequenceTensorTypeBase;
class NonTensorTypeBase;
#if !defined(DISABLE_OPTIONAL_TYPE)
class OptionalTypeBase;
#endif
class PrimitiveDataTypeBase;
class Tensor;
class TensorSeq;
@ -132,9 +134,11 @@ class DataTypeImpl {
}
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
virtual const OptionalTypeBase* AsOptionalType() const {
return nullptr;
}
#endif
virtual const NonTensorTypeBase* AsNonTensorType() const {
return nullptr;
@ -319,11 +323,13 @@ struct IsSparseTensorContainedType : public IsAnyOf<T, float, uint8_t, int8_t, u
};
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
/// Tells if the specified type is one of ORT types
/// that can be contained within an optional struct.
template <typename T>
struct IsOptionalOrtType : public IsAnyOf<T, Tensor, TensorSeq> {
};
#endif
/// This template's Get() returns a corresponding MLDataType
/// It dispatches the call to either GetTensorType<>() or
@ -505,6 +511,49 @@ class TensorType : public TensorTypeBase {
}
};
#if defined(DISABLE_OPTIONAL_TYPE)
/// Common base-class for all disabled types. We need DataTypeImpl::ToString to work in a minimal build
/// with disabled types to keep the ORT format model kernel hashes stable.
class DisabledTypeBase : public DataTypeImpl {
public:
static MLDataType Type();
bool IsCompatible(const ONNX_NAMESPACE::TypeProto&) const override {
// We always want to return false for the IsCompatible() for a disabled type
// because this will ensure that no kernel supporting the disabled type will
// be matched to a model node requiring that type and the model load will
// result in failure.
return false;
}
size_t Size() const override {
ORT_THROW("Type is disabled in this build.");
}
DeleteFunc GetDeleteFunc() const override {
ORT_THROW("Type is disabled in this build.");
}
// This must work
const ONNX_NAMESPACE::TypeProto* GetTypeProto() const override;
ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(DisabledTypeBase);
protected:
// This must work
ONNX_NAMESPACE::TypeProto& MutableTypeProto();
DisabledTypeBase();
~DisabledTypeBase() override;
private:
struct Impl;
Impl* impl_;
};
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
/// Common base-class for all sparse-tensors (with different element types).
class SparseTensorTypeBase : public DataTypeImpl {
@ -569,6 +618,8 @@ class SparseTensorType : public SparseTensorTypeBase {
#endif // !defined(DISABLE_SPARSE_TENSORS)
/// Common base-class for all optional types.
#if !defined(DISABLE_OPTIONAL_TYPE)
class OptionalTypeBase : public DataTypeImpl {
public:
static MLDataType Type();
@ -613,18 +664,28 @@ class OptionalTypeBase : public DataTypeImpl {
struct Impl;
Impl* impl_;
};
#endif
// Derive from OptionalTypeBase if the Optional type support is enabled,
// else derive from DisabledTypeBase
template <typename T, typename elemT>
class OptionalType : public OptionalTypeBase {
class OptionalType :
#if !defined(DISABLE_OPTIONAL_TYPE)
public OptionalTypeBase
#else
public DisabledTypeBase
#endif
{
public:
static MLDataType Type();
#if !defined(DISABLE_OPTIONAL_TYPE)
static_assert(data_types_internal::IsOptionalOrtType<T>::value,
"Requires one of the supported types: Tensor or TensorSeq");
static_assert(data_types_internal::IsTensorContainedType<elemT>::value,
"Requires one of the tensor fundamental types");
static MLDataType Type();
MLDataType GetElementType() const override {
if (std::is_same<T, Tensor>::value) {
return DataTypeImpl::GetTensorType<elemT>();
@ -635,6 +696,7 @@ class OptionalType : public OptionalTypeBase {
ORT_ENFORCE(false, "Unsupported optional type");
}
}
#endif
private:
OptionalType() {

View file

@ -81,6 +81,7 @@ class OpKernelContext {
SparseTensor* OutputSparse(int index, const TensorShape& shape);
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
// Use this API to output a "None" of a specific type (e.g. Tensor) at specified index
template <typename T>
void OutputOptionalWithoutData(int index) {
@ -92,6 +93,7 @@ class OpKernelContext {
type,
type->GetDeleteFunc());
}
#endif
// Retrieve indexed shape obtained from memory planning before actual
// computation. If the indexed shape cannot be inferred, this function returns

View file

@ -49,7 +49,6 @@ struct OrtValue {
template <typename T>
const T& Get() const {
ORT_ENFORCE(onnxruntime::DataTypeImpl::GetType<T>() == type_, onnxruntime::DataTypeImpl::GetType<T>(), " != ", type_);
ORT_ENFORCE(IsAllocated(), "OrtValue contains no data");
return *static_cast<T*>(data_.get());
}

View file

@ -447,12 +447,16 @@ class PlannerImpl {
// TODO this should be an error case, needs more investigation
continue;
}
#if !defined(DISABLE_OPTIONAL_TYPE)
// Make sure optional types are not up for re-use as we aren't quite
// sure if the re-used tensor will be a None or otherwise. This cannot
// be determined statically.
if (IsOptionalType(*p_node_arg)) {
continue;
}
#endif
auto& available_memory_info = AllocPlan(p_node_arg->Name()).location;
if (!(available_memory_info == required_memory_info)) continue;
auto p_available_buffer_shape = context_.GetShape(*p_node_arg);
@ -1142,10 +1146,12 @@ class PlannerImpl {
return !utils::HasTensorType(type_proto);
}
#if !defined(DISABLE_OPTIONAL_TYPE)
static bool IsOptionalType(const onnxruntime::NodeArg& nodearg) {
const auto* type_proto = nodearg.TypeAsProto();
return type_proto->value_case() == ONNX_NAMESPACE::TypeProto::kOptionalType;
}
#endif
//For in-place reuse tensors, the lifetime is the union of all the tensors that tensors that use that buffer
#if !defined(ORT_MINIMAL_BUILD) && defined(ORT_MEMORY_PROFILE)

View file

@ -151,6 +151,11 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_SparseTensor& tensor_proto,
const ONNX_NAMESPACE::TypeProto_SparseTensor& type_proto);
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Optional& optional_proto,
const ONNX_NAMESPACE::TypeProto_Optional& type_proto);
#endif
#if !defined(DISABLE_ML_OPS)
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Map& map_proto,
const ONNX_NAMESPACE::TypeProto_Map& type_proto);
@ -196,6 +201,11 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Map& map_proto,
case TypeProto::ValueCase::kSparseTensorType:
result = IsCompatible(lhs.value_type().sparse_tensor_type(), rhs.value_type().sparse_tensor_type());
break;
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::ValueCase::kOptionalType:
result = IsCompatible(lhs.value_type().optional_type(), rhs.value_type().optional_type());
break;
#endif
default:
ORT_ENFORCE(false);
@ -231,6 +241,11 @@ static bool IsCompatible(const ONNX_NAMESPACE::TypeProto& type_proto_1,
case TypeProto::ValueCase::kSparseTensorType:
result = IsCompatible(type_proto_1.sparse_tensor_type(), type_proto_2.sparse_tensor_type());
break;
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::ValueCase::kOptionalType:
result = IsCompatible(type_proto_1.optional_type(), type_proto_2.optional_type());
break;
#endif
default:
ORT_ENFORCE(false);
@ -247,10 +262,12 @@ bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Sequence& sequence_proto,
return IsCompatible(sequence_proto.elem_type(), type_proto.elem_type());
}
#if !defined(DISABLE_OPTIONAL_TYPE)
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Optional& optional_proto,
const ONNX_NAMESPACE::TypeProto_Optional& type_proto) {
return IsCompatible(optional_proto.elem_type(), type_proto.elem_type());
}
#endif
bool IsCompatible(const ONNX_NAMESPACE::TypeProto_Opaque& opaque_proto,
const ONNX_NAMESPACE::TypeProto_Opaque& type_proto) {
@ -493,6 +510,7 @@ MLDataType SequenceTensorTypeBase::Type() {
return &sequence_tensor_base;
}
#if !defined(DISABLE_OPTIONAL_TYPE)
///// OptionalTypeBase
struct OptionalTypeBase::Impl : public data_types_internal::TypeProtoImpl {
@ -531,6 +549,33 @@ MLDataType OptionalTypeBase::Type() {
static OptionalTypeBase optional_type_base;
return &optional_type_base;
}
#endif
/// DisabledTypeBase
#if defined(DISABLE_OPTIONAL_TYPE)
struct DisabledTypeBase::Impl : public data_types_internal::TypeProtoImpl {
};
DisabledTypeBase::DisabledTypeBase() : impl_(new Impl()) {}
DisabledTypeBase::~DisabledTypeBase() {
delete impl_;
}
const ONNX_NAMESPACE::TypeProto* DisabledTypeBase::GetTypeProto() const {
return impl_->GetProto();
}
ONNX_NAMESPACE::TypeProto& DisabledTypeBase::MutableTypeProto() {
return impl_->MutableTypeProto();
}
MLDataType DisabledTypeBase::Type() {
static DisabledTypeBase disabled_base;
return &disabled_base;
}
#endif
/// NoTensorTypeBase
struct NonTensorTypeBase::Impl : public data_types_internal::TypeProtoImpl {};
@ -695,11 +740,13 @@ ORT_REGISTER_OPTIONAL_ORT_TYPE(TensorSeq)
reg_fn(mltype); \
}
#if !defined(DISABLE_OPTIONAL_TYPE)
#define REGISTER_OPTIONAL_PROTO(ORT_TYPE, TYPE, reg_fn) \
{ \
MLDataType mltype = DataTypeImpl::GetOptionalType<ORT_TYPE, TYPE>(); \
reg_fn(mltype); \
}
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
#define REGISTER_SPARSE_TENSOR_PROTO(TYPE, reg_fn) \
@ -781,6 +828,7 @@ void RegisterAllProtos(const std::function<void(MLDataType)>& reg_fn) {
REGISTER_ONNX_PROTO(VectorMapInt64ToFloat, reg_fn);
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
#define REGISTER_OPTIONAL_PROTO_ORT_TYPE(ORT_TYPE, reg_fn) \
REGISTER_OPTIONAL_PROTO(ORT_TYPE, int32_t, reg_fn); \
REGISTER_OPTIONAL_PROTO(ORT_TYPE, float, reg_fn); \
@ -799,6 +847,7 @@ void RegisterAllProtos(const std::function<void(MLDataType)>& reg_fn) {
REGISTER_OPTIONAL_PROTO_ORT_TYPE(Tensor, reg_fn);
REGISTER_OPTIONAL_PROTO_ORT_TYPE(TensorSeq, reg_fn);
#endif
}
} // namespace data_types_internal
@ -1030,18 +1079,6 @@ std::vector<MLDataType> GetOptionalTensorTypesFromTypeList() {
return boost::mp11::mp_apply<GetOptionalTensorTypesImpl, L>{}();
}
template <typename... ElementTypes>
struct GetSequenceTensorTypesImpl {
std::vector<MLDataType> operator()() const {
return {DataTypeImpl::GetSequenceTensorType<ElementTypes>()...};
}
};
template <typename L>
std::vector<MLDataType> GetSequenceTensorTypesFromTypeList() {
return boost::mp11::mp_apply<GetSequenceTensorTypesImpl, L>{}();
}
template <typename... ElementTypes>
struct GetOptionalSequenceTensorTypesImpl {
std::vector<MLDataType> operator()() const {
@ -1054,6 +1091,18 @@ std::vector<MLDataType> GetOptionalSequenceTensorTypesFromTypeList() {
return boost::mp11::mp_apply<GetOptionalSequenceTensorTypesImpl, L>{}();
}
template <typename... ElementTypes>
struct GetSequenceTensorTypesImpl {
std::vector<MLDataType> operator()() const {
return {DataTypeImpl::GetSequenceTensorType<ElementTypes>()...};
}
};
template <typename L>
std::vector<MLDataType> GetSequenceTensorTypesFromTypeList() {
return boost::mp11::mp_apply<GetSequenceTensorTypesImpl, L>{}();
}
} // namespace
const std::vector<MLDataType>& DataTypeImpl::AllFixedSizeTensorExceptHalfTypes() {
@ -1200,10 +1249,12 @@ ContainerChecker::ContainerChecker(MLDataType ml_type) {
types_.emplace_back(ContainerType::kSequence, TensorProto_DataType_UNDEFINED);
type_proto = &type_proto->sequence_type().elem_type();
break;
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::ValueCase::kOptionalType:
types_.emplace_back(ContainerType::kOptional, TensorProto_DataType_UNDEFINED);
type_proto = &type_proto->optional_type().elem_type();
break;
#endif
case TypeProto::ValueCase::kOpaqueType:
// We do not handle this and terminate here
types_.emplace_back(ContainerType::kOpaque,

View file

@ -687,13 +687,21 @@ Status ExecutionFrame::AllocateAsPerAllocationPlan(OrtValue& ort_value, int ort_
return status;
}
if (ml_type->IsTensorType() || utils::IsOptionalTensor(ml_type)) {
if (ml_type->IsTensorType()
#if !defined(DISABLE_OPTIONAL_TYPE)
|| utils::IsOptionalTensor(ml_type)
#endif
) {
ORT_ENFORCE(shape, "Allocation of tensor types requires a shape.");
// tensors / optional tensors
#if !defined(DISABLE_OPTIONAL_TYPE)
const auto* ml_data_type = ml_type->IsTensorType()
? static_cast<const TensorTypeBase*>(ml_type)->GetElementType()
: utils::GetElementTypeFromOptionalTensor(ml_type);
#else
const auto* ml_data_type = static_cast<const TensorTypeBase*>(ml_type)->GetElementType();
#endif
AllocKind alloc_kind = per_alloc_plan.alloc_kind;
switch (alloc_kind) {
@ -741,7 +749,11 @@ Status ExecutionFrame::AllocateAsPerAllocationPlan(OrtValue& ort_value, int ort_
// Model load should have failed so this should be unreachable
ORT_THROW("SparseTensor is not supported in this build.");
#endif
} else if (ml_type->IsTensorSequenceType() || utils::IsOptionalSeqTensor(ml_type)) {
} else if (ml_type->IsTensorSequenceType()
#if !defined(DISABLE_OPTIONAL_TYPE)
|| utils::IsOptionalSeqTensor(ml_type)
#endif
) {
AllocKind alloc_kind = per_alloc_plan.alloc_kind;
if (alloc_kind == AllocKind::kReuse) {

View file

@ -11,6 +11,7 @@ namespace onnxruntime {
namespace utils {
MLDataType GetMLDataType(const onnxruntime::NodeArg& arg);
#if !defined(DISABLE_OPTIONAL_TYPE)
inline bool IsOptionalTensor(MLDataType type) {
return type->IsOptionalType() &&
type->AsOptionalType()->GetElementType()->IsTensorType();
@ -40,5 +41,7 @@ inline MLDataType GetElementTypeFromOptionalSeqTensor(MLDataType type) {
->AsSequenceTensorType()
->GetElementType();
}
#endif
} // namespace utils
} // namespace onnxruntime

View file

@ -123,6 +123,7 @@ inline bool HasTensorType(const ONNX_NAMESPACE::TypeProto& type_proto) {
return type_proto.value_case() == ONNX_NAMESPACE::TypeProto::kTensorType;
}
#if !defined(DISABLE_OPTIONAL_TYPE)
inline bool HasOptionalTensorType(const ONNX_NAMESPACE::TypeProto& type_proto) {
return type_proto.value_case() == ONNX_NAMESPACE::TypeProto::kOptionalType &&
type_proto.optional_type().elem_type().value_case() == ONNX_NAMESPACE::TypeProto::kTensorType;
@ -155,6 +156,7 @@ inline ONNX_NAMESPACE::TypeProto* GetMutableOptionalTypeProto(ONNX_NAMESPACE::Ty
inline bool HasElemType(const ONNX_NAMESPACE::TypeProto_Optional& opt_proto) {
return opt_proto.elem_type().value_case() != ONNX_NAMESPACE::TypeProto::VALUE_NOT_SET;
}
#endif
inline bool HasElemType(const ONNX_NAMESPACE::TypeProto_Tensor& ten_proto) {
return ten_proto.elem_type() != ONNX_NAMESPACE::TensorProto::UNDEFINED;
@ -191,10 +193,12 @@ inline bool HasElementType(const ONNX_NAMESPACE::TypeProto& type_proto) {
}
#endif // !defined(DISABLE_SPARSE_TENSORS)
#if !defined(DISABLE_OPTIONAL_TYPE)
if (HasOptionalTensorType(type_proto) &&
HasShape(GetOptionalTypeProto(type_proto).tensor_type())) {
return true;
}
#endif
return false;
}
@ -222,9 +226,11 @@ inline const ONNX_NAMESPACE::TensorShapeProto& GetShape(const ONNX_NAMESPACE::Ty
}
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
if (HasOptionalTensorType(type_proto) && HasShape(GetOptionalTypeProto(type_proto).tensor_type())) {
return GetOptionalTypeProto(type_proto).tensor_type().shape();
}
#endif
ORT_THROW("TypeProto must have shape for this to run");
}

View file

@ -69,30 +69,42 @@ static bool UsingLatestOnnxOpset(const DomainToVersionMap& opset_versions) {
static Status MergeShapeInfo(const std::string& output_name,
const TypeProto& source, TypeProto& target,
bool strict, const logging::Logger& logger) {
#if !defined(DISABLE_SPARSE_TENSORS)
if (!(utils::HasTensorType(source) && utils::HasTensorType(target)) &&
!(utils::HasOptionalTensorType(source) && utils::HasOptionalTensorType(target)) &&
!(utils::HasSparseTensorType(source) && utils::HasSparseTensorType(target))) {
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL,
"Source and target must both be either tensors, "
"optional tensors, or sparse tensors");
}
#else
if (!(utils::HasTensorType(source) && utils::HasTensorType(target))) {
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL,
"Source and target must both be tensors");
}
if (!(utils::HasTensorType(source) && utils::HasTensorType(target))
#if !defined(DISABLE_OPTIONAL_TYPE)
&& !(utils::HasOptionalTensorType(source) && utils::HasOptionalTensorType(target))
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
&& !(utils::HasSparseTensorType(source) && utils::HasSparseTensorType(target))
#endif
) {
std::ostringstream ss;
ss << "Source and target must both be tensors";
#if !defined(DISABLE_OPTIONAL_TYPE)
ss << " , or optional typed entities";
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
ss << " , or sparse tensors";
#endif
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, ss.str());
}
auto status = Status::OK();
ORT_TRY {
if (utils::HasTensorType(source)) {
ONNX_NAMESPACE::mergeInShapeInfo(source.tensor_type(), *target.mutable_tensor_type());
} else if (utils::HasOptionalTensorType(source)) {
}
#if !defined(DISABLE_OPTIONAL_TYPE)
else if (utils::HasOptionalTensorType(source)) {
ONNX_NAMESPACE::mergeInShapeInfo(utils::GetOptionalTypeProto(source).tensor_type(),
*utils::GetMutableOptionalTypeProto(target)->mutable_tensor_type());
}
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
else {
ONNX_NAMESPACE::mergeInShapeInfo(source.sparse_tensor_type(), *target.mutable_sparse_tensor_type());
@ -112,9 +124,13 @@ static Status MergeShapeInfo(const std::string& output_name,
<< ". Falling back to lenient merge.";
if (utils::HasTensorType(source)) {
ONNX_NAMESPACE::UnionShapeInfo(utils::GetShape(source), *target.mutable_tensor_type());
} else if (utils::HasOptionalTensorType(source)) {
}
#if !defined(DISABLE_OPTIONAL_TYPE)
else if (utils::HasOptionalTensorType(source)) {
ONNX_NAMESPACE::UnionShapeInfo(utils::GetShape(source), *utils::GetMutableOptionalTypeProto(target)->mutable_tensor_type());
}
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
else {
ONNX_NAMESPACE::UnionShapeInfo(utils::GetShape(source), *target.mutable_sparse_tensor_type());
@ -233,6 +249,8 @@ const TensorShapeProto* NodeArg::Shape() const {
return nullptr;
}
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::kOptionalType: {
// Shape is applicable only for optional tensor type
if (utils::HasOptionalTensorType(*type) &&
@ -241,6 +259,8 @@ const TensorShapeProto* NodeArg::Shape() const {
}
return nullptr;
}
#endif
case TypeProto::kSequenceType:
case TypeProto::kMapType:
case TypeProto::kOpaqueType:
@ -285,6 +305,8 @@ void NodeArg::SetShape(const TensorShapeProto& shape) {
*(node_arg_info_.mutable_type()->mutable_sparse_tensor_type()->mutable_shape()) = shape;
break;
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::kOptionalType:
// Set shape only for optional tensors
if (utils::HasOptionalTensorType(node_arg_info_.type())) {
@ -293,6 +315,7 @@ void NodeArg::SetShape(const TensorShapeProto& shape) {
->mutable_shape()) = shape;
}
break;
#endif
case TypeProto::kSequenceType:
case TypeProto::kMapType:
case TypeProto::kOpaqueType:
@ -313,6 +336,8 @@ void NodeArg::ClearShape() {
node_arg_info_.mutable_type()->mutable_sparse_tensor_type()->clear_shape();
break;
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::kOptionalType:
// Clear shape only for optional tensors
if (utils::HasOptionalTensorType(node_arg_info_.type())) {
@ -321,6 +346,8 @@ void NodeArg::ClearShape() {
->clear_shape();
}
break;
#endif
case TypeProto::kSequenceType:
case TypeProto::kMapType:
case TypeProto::kOpaqueType:
@ -410,15 +437,19 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu
}
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::kOptionalType: {
if ((utils::HasOptionalTensorType(input_type) && !utils::HasOptionalTensorType(current_type)) ||
(!utils::HasOptionalTensorType(input_type) && utils::HasOptionalTensorType(current_type))) {
bool is_input_type_optional_tensor_type = utils::HasOptionalTensorType(input_type);
bool is_current_type_optional_tensor_type = utils::HasOptionalTensorType(current_type);
// Check for homogeneity within optional type
if (is_input_type_optional_tensor_type != is_current_type_optional_tensor_type) {
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Optional Type mismatch. Expected: ", ONNX_NAMESPACE::Utils::DataTypeUtils::ToType(current_type),
" . Got: ", ONNX_NAMESPACE::Utils::DataTypeUtils::ToType(input_type));
}
// Updating element type and shape is only applicable for optional tensors
if (utils::HasOptionalTensorType(input_type)) {
if (is_input_type_optional_tensor_type) {
const auto& optional_input_type = utils::GetOptionalTypeProto(input_type);
auto& optional_current_type = *utils::GetMutableOptionalTypeProto(current_type);
@ -444,6 +475,7 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu
break;
}
#endif
case TypeProto::kSequenceType:
case TypeProto::kMapType:
@ -1906,10 +1938,12 @@ bool FullyDefinedType(const TypeProto& type_proto) {
auto& seq_type = type_proto.sequence_type();
return utils::HasElemType(seq_type) && FullyDefinedType(seq_type.elem_type());
}
#if !defined(DISABLE_OPTIONAL_TYPE)
case TypeProto::kOptionalType: {
auto& optional_type = type_proto.optional_type();
return utils::HasElemType(optional_type) && FullyDefinedType(optional_type.elem_type());
}
#endif
case TypeProto::kMapType: {
auto& map_type = type_proto.map_type();
return utils::HasKeyType(map_type) &&
@ -2346,11 +2380,15 @@ Status Graph::InferAndVerifyTypeMatch(Node& node, const OpSchema& op, const Reso
TypeProto merge_target;
if (utils::HasTensorType(onnx_inferred_type)) {
*merge_target.mutable_tensor_type()->mutable_shape() = *output_def->Shape();
} else if (utils::HasOptionalTensorType(onnx_inferred_type)) {
}
#if !defined(DISABLE_OPTIONAL_TYPE)
else if (utils::HasOptionalTensorType(onnx_inferred_type)) {
*utils::GetMutableOptionalTypeProto(merge_target)
->mutable_tensor_type()
->mutable_shape() = *output_def->Shape();
}
#endif
#if !defined(DISABLE_SPARSE_TENSORS)
else if (utils::HasSparseTensorType(onnx_inferred_type)) {
*merge_target.mutable_sparse_tensor_type()->mutable_shape() = *output_def->Shape();

View file

@ -102,6 +102,7 @@ ONNX_CPU_OPERATOR_KERNEL(If,
.TypeConstraint("B", DataTypeImpl::GetTensorType<bool>())
.TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()),
If);
If::Info::Info(const onnxruntime::Node& node, const GraphViewer& subgraph_in) : subgraph(subgraph_in) {
num_implicit_inputs = static_cast<int>(node.ImplicitInputDefs().size());
used_implicit_inputs = std::vector<bool>(num_implicit_inputs, true);
@ -151,11 +152,13 @@ class IfImpl {
// track where the fetches provided to subgraph execution were allocated.
std::vector<std::pair<AllocationType, OrtValue>> outputs_;
#if !defined(DISABLE_OPTIONAL_TYPE)
// track which outputs are optional tensor types
std::vector<int> optional_tensor_type_subgraph_outputs_;
// track which outputs are optional tensor sequence types
std::vector<int> optional_tensor_sequence_type_subgraph_outputs_;
#endif
};
void If::Init(const OpKernelInfo& info) {
@ -280,18 +283,26 @@ Status IfImpl::AllocateOutputTensors() {
const auto& graph_outputs = info_.subgraph.GetOutputs();
#if !defined(DISABLE_OPTIONAL_TYPE)
// The number of optional type outputs can be atmost the total
// number of subgraph outputs (it is okay to over-allocate)
optional_tensor_type_subgraph_outputs_.reserve(graph_outputs.size());
optional_tensor_sequence_type_subgraph_outputs_.reserve(graph_outputs.size());
#endif
for (auto& graph_output : graph_outputs) {
const auto* graph_output_type = graph_output->TypeAsProto();
#if !defined(DISABLE_OPTIONAL_TYPE)
bool is_optional_tensor = utils::HasOptionalTensorType(*graph_output_type);
bool is_optional_tensor_sequence = utils::HasOptionalTensorSequenceType(*graph_output_type);
#endif
if (graph_output_type->has_tensor_type() || is_optional_tensor) {
if (graph_output_type->has_tensor_type()
#if !defined(DISABLE_OPTIONAL_TYPE)
|| is_optional_tensor
#endif
) {
auto* graph_output_shape = graph_output->Shape();
bool symbolic_dim_in_shape = false;
@ -315,22 +326,29 @@ Status IfImpl::AllocateOutputTensors() {
// we still need a value to put in the feeds we give to the execution frame, so just use an empty MLValue
outputs_.push_back({AllocationType::Delayed, {}});
}
} else if (graph_output_type->has_sequence_type() || is_optional_tensor_sequence) {
} else if (graph_output_type->has_sequence_type()
#if !defined(DISABLE_OPTIONAL_TYPE)
|| is_optional_tensor_sequence
#endif
) {
auto* seq_tensor = context_.Output<TensorSeq>(index);
if (!seq_tensor)
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to create output tensor for ", graph_output->Name());
outputs_.push_back({AllocationType::IfOutput, *context_.GetOutputMLValue(index)});
} else {
// Shouldn't hit this
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Only tensors or sequence of tensors are supported");
// Shouldn't hit this as the kernel assignment logic should check for the types before assigning this kernel
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
"Only tensors, tensor sequence, optional tensor, and optional tensor sequence types are supported");
}
#if !defined(DISABLE_OPTIONAL_TYPE)
// track optional type outputs - we will use them later
if (is_optional_tensor) {
optional_tensor_type_subgraph_outputs_.push_back(index);
} else if (is_optional_tensor_sequence) {
optional_tensor_sequence_type_subgraph_outputs_.push_back(index);
}
#endif
++index;
}
@ -399,6 +417,7 @@ Status IfImpl::Execute(const FeedsFetchesManager& ffm) {
ORT_RETURN_IF_ERROR(status);
#if !defined(DISABLE_OPTIONAL_TYPE)
// Deal with Nones in fetches
for (auto& output_index : optional_tensor_type_subgraph_outputs_) {
// "None" - reflect Nones in the output of If
@ -415,6 +434,7 @@ Status IfImpl::Execute(const FeedsFetchesManager& ffm) {
context_.OutputOptionalWithoutData<TensorSeq>(output_index);
}
}
#endif
return status;
}

View file

@ -130,6 +130,7 @@ ONNX_CPU_OPERATOR_KERNEL(Loop,
.TypeConstraint("B", DataTypeImpl::GetTensorType<bool>())
.TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()),
Loop);
Loop::Info::Info(const onnxruntime::Node& node, const GraphViewer& subgraph_in)
: subgraph(subgraph_in) {
num_loop_carried_vars = static_cast<int>(node.InputDefs().size()) - 2; // skip 'M' and 'cond'
@ -509,6 +510,7 @@ Status LoopImpl::Execute(const FeedsFetchesManager& ffm) {
// as we need the final shape.
auto copy_mlvalue_to_output = [this](OrtValue& input, int output_idx,
int64_t iter_num_value, const TypeProto& tp) {
#if !defined(DISABLE_OPTIONAL_TYPE)
// Only Optional type can be None (i.e.) not have data
if (tp.has_optional_type() && !input.IsAllocated()) {
// We can't rely on the input OrtValue containing type information
@ -519,6 +521,10 @@ Status LoopImpl::Execute(const FeedsFetchesManager& ffm) {
static_cast<OpKernelContext*>(&context_),
output_idx));
} else if (input.IsTensor()) {
#else
ORT_UNUSED_PARAMETER(tp);
if (input.IsTensor()) {
#endif
const auto& input_tensor = input.Get<Tensor>();
Tensor* output = context_.Output(output_idx, input_tensor.Shape());
// Safely use the IDataTransfer abstraction as we only allow using
@ -556,6 +562,7 @@ Status LoopImpl::Execute(const FeedsFetchesManager& ffm) {
output->SetElements(std::move(tensors));
}
}
return Status::OK();
};

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#if !defined(DISABLE_OPTIONAL_TYPE)
#include "optional_ops.h"
#include "core/framework/ort_value.h"
#include "core/providers/cpu/tensor/utils.h"
@ -155,3 +157,5 @@ Status OptionalGetElement::Compute(OpKernelContext* ctx) const {
}
} // namespace onnxruntime
#endif

View file

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#if !defined(DISABLE_OPTIONAL_TYPE)
#pragma once
#include "core/common/common.h"
@ -40,3 +42,5 @@ class OptionalGetElement final : public OpKernel {
};
} // namespace onnxruntime
#endif

View file

@ -51,4 +51,5 @@ ONNX_CPU_OPERATOR_KERNEL(
16,
KernelDefBuilder().TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()).Alias(0, 0),
IdentityOp<false>);
} // namespace onnxruntime

View file

@ -29,6 +29,7 @@ class IdentityOp final : public OpKernel {
const auto* input_ort_value = context->GetInputOrtValue(0);
#if !defined(DISABLE_OPTIONAL_TYPE)
// Only Optional type can be None (i.e.) not have data
if (input_type_proto->has_optional_type() && !input_ort_value->IsAllocated()) {
// We can't rely on the input OrtValue containing type information
@ -38,6 +39,9 @@ class IdentityOp final : public OpKernel {
ORT_RETURN_IF_ERROR(utils::OutputOptionalWithoutDataHelper(*input_type_proto, context, 0));
return Status::OK();
}
#else
ORT_UNUSED_PARAMETER(input_type_proto);
#endif
if (input_ort_value->IsTensor()) {
const auto* X = &input_ort_value->Get<Tensor>();

View file

@ -252,9 +252,11 @@ struct ProviderHost {
virtual int int64s__size(const ONNX_NAMESPACE::int64s* p) = 0;
virtual const int64_t& int64s__Get(const ONNX_NAMESPACE::int64s* p, int index) = 0;
#if !defined(DISABLE_OPTIONAL_TYPE)
// TypeProto_Optional
virtual const ONNX_NAMESPACE::TypeProto& TypeProto_Optional__elem_type(const ONNX_NAMESPACE::TypeProto_Optional* p) = 0;
virtual ONNX_NAMESPACE::TypeProto* TypeProto_Optional__mutable_elem_type(ONNX_NAMESPACE::TypeProto_Optional* p) = 0;
#endif
// TypeProto_Sequence
virtual const ONNX_NAMESPACE::TypeProto& TypeProto_Sequence__elem_type(const ONNX_NAMESPACE::TypeProto_Sequence* p) = 0;
@ -283,8 +285,10 @@ struct ProviderHost {
virtual ONNX_NAMESPACE::TypeProto_SparseTensor* TypeProto__mutable_sparse_tensor_type(ONNX_NAMESPACE::TypeProto* p) = 0;
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
virtual const ONNX_NAMESPACE::TypeProto_Optional& TypeProto__optional_type(const ONNX_NAMESPACE::TypeProto* p) = 0;
virtual ONNX_NAMESPACE::TypeProto_Optional* TypeProto__mutable_optional_type(ONNX_NAMESPACE::TypeProto* p) = 0;
#endif
virtual const ONNX_NAMESPACE::TypeProto_Sequence& TypeProto__sequence_type(const ONNX_NAMESPACE::TypeProto* p) = 0;
virtual ONNX_NAMESPACE::TypeProto_Sequence* TypeProto__mutable_sequence_type(ONNX_NAMESPACE::TypeProto* p) = 0;

View file

@ -225,11 +225,13 @@ struct TypeProto_SparseTensor final {
};
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
struct TypeProto_Optional final {
const TypeProto& elem_type() const { return g_host->TypeProto_Optional__elem_type(this); }
TypeProto* mutable_elem_type() { return g_host->TypeProto_Optional__mutable_elem_type(this); }
PROVIDER_DISALLOW_ALL(TypeProto_Optional)
};
#endif
struct TypeProto_Sequence final {
const TypeProto& elem_type() const { return g_host->TypeProto_Sequence__elem_type(this); }
@ -246,8 +248,10 @@ struct TypeProto final {
TypeProto_SparseTensor* mutable_sparse_tensor_type() { return g_host->TypeProto__mutable_sparse_tensor_type(this); }
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
const TypeProto_Optional& optional_type() const { return g_host->TypeProto__optional_type(this); }
TypeProto_Optional* mutable_optional_type() { return g_host->TypeProto__mutable_optional_type(this); }
#endif
const TypeProto_Sequence& sequence_type() const { return g_host->TypeProto__sequence_type(this); }
TypeProto_Sequence* mutable_sequence_type() { return g_host->TypeProto__mutable_sequence_type(this); }

View file

@ -7,6 +7,7 @@
namespace onnxruntime {
namespace utils {
#if !defined(DISABLE_OPTIONAL_TYPE)
common::Status OutputOptionalWithoutDataHelper(const ONNX_NAMESPACE::TypeProto& input_type_proto,
OpKernelContext* context, int output_index) {
if (utils::HasOptionalTensorType(input_type_proto)) {
@ -21,6 +22,7 @@ common::Status OutputOptionalWithoutDataHelper(const ONNX_NAMESPACE::TypeProto&
return Status::OK();
}
#endif
} // namespace utils
} // namespace onnxruntime

View file

@ -10,8 +10,10 @@
namespace onnxruntime {
namespace utils {
#if !defined(DISABLE_OPTIONAL_TYPE)
common::Status OutputOptionalWithoutDataHelper(const ONNX_NAMESPACE::TypeProto& input_type_proto,
OpKernelContext* context, int output_index);
#endif
} // namespace utils
} // namespace onnxruntime

View file

@ -1572,18 +1572,26 @@ common::Status InferenceSession::ValidateInputs(const std::vector<std::string>&
auto expected_type = iter->second.ml_data_type;
auto& input_ml_value = feeds.at(i);
if (input_ml_value.IsTensor()) {
if (!expected_type->IsTensorType() &&
!utils::IsOptionalTensor(expected_type)) {
if (!expected_type->IsTensorType()
#if !defined(DISABLE_OPTIONAL_TYPE)
&& !utils::IsOptionalTensor(expected_type)
#endif
) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input with name: ", feed_name,
" is not expected to be of type tensor.");
}
// check for type
#if !defined(DISABLE_OPTIONAL_TYPE)
auto expected_element_type = expected_type->IsTensorType()
? expected_type
->AsTensorType()
->GetElementType()
: utils::GetElementTypeFromOptionalTensor(expected_type);
#else
auto expected_element_type = expected_type->AsTensorType()->GetElementType();
#endif
auto input_element_type = input_ml_value.Get<Tensor>().DataType();
ORT_RETURN_IF_ERROR_SESSIONID_(CheckTypes(input_element_type, expected_element_type, "tensor"));
@ -1615,17 +1623,24 @@ common::Status InferenceSession::ValidateInputs(const std::vector<std::string>&
#endif
} else if (input_ml_value.IsTensorSequence()) {
if (!expected_type->IsTensorSequenceType() &&
!utils::IsOptionalSeqTensor(expected_type)) {
if (!expected_type->IsTensorSequenceType()
#if !defined(DISABLE_OPTIONAL_TYPE)
&& !utils::IsOptionalSeqTensor(expected_type)
#endif
) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input with name: ", feed_name,
" is not expected to be of type tensor sequence.");
}
#if !defined(DISABLE_OPTIONAL_TYPE)
auto expected_element_type = expected_type->IsTensorSequenceType()
? expected_type
->AsSequenceTensorType()
->GetElementType()
: utils::GetElementTypeFromOptionalSeqTensor(expected_type);
#else
auto expected_element_type = expected_type->AsSequenceTensorType()->GetElementType();
#endif
auto input_element_type = input_ml_value.Get<TensorSeq>().DataType();
ORT_RETURN_IF_ERROR_SESSIONID_(CheckTypes(input_element_type, expected_element_type, "seq"));

View file

@ -315,9 +315,11 @@ struct ProviderHostImpl : ProviderHost {
int int64s__size(const ONNX_NAMESPACE::int64s* p) override { return p->size(); }
const int64_t& int64s__Get(const ONNX_NAMESPACE::int64s* p, int index) override { return p->Get(index); }
#if !defined(DISABLE_OPTIONAL_TYPE)
// TypeProto_Optional (wrapped)
const ONNX_NAMESPACE::TypeProto& TypeProto_Optional__elem_type(const ONNX_NAMESPACE::TypeProto_Optional* p) override { return p->elem_type(); }
ONNX_NAMESPACE::TypeProto* TypeProto_Optional__mutable_elem_type(ONNX_NAMESPACE::TypeProto_Optional* p) override { return p->mutable_elem_type(); }
#endif
// TypeProto_Sequence (wrapped)
const ONNX_NAMESPACE::TypeProto& TypeProto_Sequence__elem_type(const ONNX_NAMESPACE::TypeProto_Sequence* p) override { return p->elem_type(); }
@ -356,8 +358,10 @@ struct ProviderHostImpl : ProviderHost {
}
#endif
#if !defined(DISABLE_OPTIONAL_TYPE)
const ONNX_NAMESPACE::TypeProto_Optional& TypeProto__optional_type(const ONNX_NAMESPACE::TypeProto* p) override { return p->optional_type(); }
ONNX_NAMESPACE::TypeProto_Optional* TypeProto__mutable_optional_type(ONNX_NAMESPACE::TypeProto* p) override { return p->mutable_optional_type(); }
#endif
const ONNX_NAMESPACE::TypeProto_Sequence& TypeProto__sequence_type(const ONNX_NAMESPACE::TypeProto* p) override { return p->sequence_type(); }
ONNX_NAMESPACE::TypeProto_Sequence* TypeProto__mutable_sequence_type(ONNX_NAMESPACE::TypeProto* p) override { return p->mutable_sequence_type(); }

View file

@ -308,10 +308,12 @@ class OnnxTestCase : public ITestCase {
bool is_input, size_t i,
std::unordered_map<std::string, Ort::Value>& out) const;
#if !defined(DISABLE_OPTIONAL_TYPE)
void ConvertTestData(const ONNX_NAMESPACE::OptionalProto& test_data_pb,
onnxruntime::test::HeapBuffer& b,
bool is_input, size_t i,
std::unordered_map<std::string, Ort::Value>& out) const;
#endif
std::once_flag model_parsed_;
std::once_flag config_parsed_;
@ -445,6 +447,7 @@ static void LoadSequenceTensor(const PATH_STRING_TYPE& pb_file, ONNX_NAMESPACE::
}
}
#if !defined(DISABLE_OPTIONAL_TYPE)
template <typename PATH_STRING_TYPE>
static void LoadOptional(const PATH_STRING_TYPE& pb_file,
ONNX_NAMESPACE::OptionalProto& input_pb) {
@ -459,6 +462,8 @@ static void LoadOptional(const PATH_STRING_TYPE& pb_file,
ORT_THROW("parse file '", ToMBString(pb_file), "' failed");
}
}
#endif
void OnnxTestCase::LoadTestData(size_t id, onnxruntime::test::HeapBuffer& b,
std::unordered_map<std::string, Ort::Value>& name_data_map,
bool is_input) const {
@ -528,11 +533,15 @@ void OnnxTestCase::LoadTestData(size_t id, onnxruntime::test::HeapBuffer& b,
ONNX_NAMESPACE::SequenceProto test_pb;
LoadSequenceTensor(test_data_pb_files[i], test_pb);
ConvertTestData(test_pb, b, is_input, i, name_data_map);
} else if (value_info_proto->type().has_optional_type()) {
}
#if !defined(DISABLE_OPTIONAL_TYPE)
else if (value_info_proto->type().has_optional_type()) {
ONNX_NAMESPACE::OptionalProto test_pb;
LoadOptional(test_data_pb_files[i], test_pb);
ConvertTestData(test_pb, b, is_input, i, name_data_map);
} else {
}
#endif
else {
ORT_THROW("Unsupported type for the ", is_input ? "input " : "output ", i, " in the test runner");
}
}
@ -617,6 +626,7 @@ void OnnxTestCase::ConvertTestData(const ONNX_NAMESPACE::SequenceProto& test_dat
}
}
#if !defined(DISABLE_OPTIONAL_TYPE)
void OnnxTestCase::ConvertTestData(const ONNX_NAMESPACE::OptionalProto& test_data_pb,
onnxruntime::test::HeapBuffer& b,
bool is_input, size_t i,
@ -673,6 +683,7 @@ void OnnxTestCase::ConvertTestData(const ONNX_NAMESPACE::OptionalProto& test_dat
}
}
}
#endif
OnnxTestCase::OnnxTestCase(const std::string& test_case_name, _In_ std::unique_ptr<TestModelInfo> model,
double default_per_sample_tolerance, double default_relative_per_sample_tolerance)

View file

@ -526,71 +526,82 @@ int real_main(int argc, char* argv[], Ort::Env& env) {
};
std::set<BrokenTest> broken_tests = {
{"BERT_Squad", "test data bug"},
{"constantofshape_float_ones", "test data bug", {"onnx141", "onnx150"}},
{"constantofshape_int_zeros", "test data bug", {"onnx141", "onnx150"}},
{"convtranspose_autopad_same", "Implementation need to be adjusted for ONNX changes"},
{"cast_STRING_to_FLOAT", "Linux CI has old ONNX python package with bad test data", {"onnx141"}},
// Numpy float to string has unexpected rounding for some results given numpy default precision is meant to be 8.
// "e.g. 0.296140194 -> '0.2961402' not '0.29614019'. ORT produces the latter with precision set to 8,
// which doesn't match the expected output that was generated with numpy.
{"cast_FLOAT_to_STRING", "Numpy float to string has unexpected rounding for some results."},
{"tf_nasnet_large", "disable temporarily"},
{"tf_nasnet_mobile", "disable temporarily"},
{"tf_pnasnet_large", "disable temporarily"},
{"shrink", "test case is wrong", {"onnx141"}},
{"maxpool_with_argmax_2d_precomputed_strides", "ShapeInferenceError"},
{"tf_inception_v2", "result mismatch"},
{"tf_resnet_v1_50", "result mismatch when Conv BN Fusion is applied"},
{"tf_resnet_v1_101", "result mismatch when Conv BN Fusion is applied"},
{"tf_resnet_v1_152", "result mismatch when Conv BN Fusion is applied"},
{"mxnet_arcface", "Model is an invalid ONNX model"},
{"unique_not_sorted_without_axis", "Expected data for 'Y' is incorrect and in sorted order."},
{"cumsum_1d_reverse_exclusive", "only failing linux GPU CI. Likely build error."},
{"resize_downsample_scales_cubic_align_corners", "results mismatch with onnx tests"},
{"resize_downsample_scales_linear_align_corners", "results mismatch with onnx tests"},
{"resize_tf_crop_and_resize", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_ceil_half_pixel", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_floor_align_corners", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_round_prefer_ceil_asymmetric", "Bad onnx test output. Needs test fix."},
{"bitshift_right_uint16", "BitShift(11) uint16 support not enabled currently"},
{"bitshift_left_uint16", "BitShift(11) uint16 support not enabled currently"},
{"maxunpool_export_with_output_shape", "Invalid output in ONNX test. See https://github.com/onnx/onnx/issues/2398"},
{"training_dropout", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_default", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_default_mask", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_mask", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"adagrad", "not a registered function/op", {}}, // Op not registered.
{"adagrad_multiple", "not a registered function/op", {}}, // Op not registered.
{"adam", "not a registered function/op", {}}, // Op not registered.
{"adam_multiple", "not a registered function/op", {}}, // Op not registered.
{"gradient_of_add", "not a registered function/op", {}}, // Op not registered.
{"gradient_of_add_and_mul", "not a registered function/op", {}}, // Op not registered.
{"momentum", "not a registered function/op", {}}, // Op not registered.
{"momentum_multiple", "not a registered function/op", {}}, // Op not registered.
{"nesterov_momentum", "not a registered function/op", {}}, // Op not registered.
{"sequence_insert_at_back", "onnx currently not supporting loading segment", {}},
{"sequence_insert_at_front", "onnx currently not supporting loading segment", {}},
{"loop13_seq", "ORT api does not currently support creating empty sequences (needed for this test)", {}},
{"cast_FLOAT_to_BFLOAT16", "onnx generate bfloat tensor as uint16 type", {}},
{"cast_BFLOAT16_to_FLOAT", "onnx generate bfloat tensor as uint16 type", {}},
{"castlike_FLOAT_to_BFLOAT16", "Depends on cast.", {}},
{"castlike_BFLOAT16_to_FLOAT", "Depends on cast", {}},
{"castlike_FLOAT_to_BFLOAT16_expanded", "Depends on cast.", {}},
{"castlike_BFLOAT16_to_FLOAT_expanded", "Depends on cast", {}},
{"castlike_FLOAT_to_STRING", "Numpy float to string has unexpected rounding for some results.", {}},
{"castlike_FLOAT_to_STRING_expanded", "Numpy float to string has unexpected rounding for some results.", {}},
{"bernoulli", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_double", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_double_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_seed", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_seed_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"test_roialign_aligned_true", "Opset 16 not supported yet."},
{"test_roialign_aligned_false", "Opset 16 not supported yet."},
{"test_scatternd_add", "Opset 16 not supported yet."},
{"test_scatternd_multiply", "Opset 16 not supported yet."},
{"test_scatter_elements_with_duplicate_indices", "Opset 16 not supported yet."},
{"BERT_Squad", "test data bug"},
{"constantofshape_float_ones", "test data bug", {"onnx141", "onnx150"}},
{"constantofshape_int_zeros", "test data bug", {"onnx141", "onnx150"}},
{"convtranspose_autopad_same", "Implementation need to be adjusted for ONNX changes"},
{"cast_STRING_to_FLOAT", "Linux CI has old ONNX python package with bad test data", {"onnx141"}},
// Numpy float to string has unexpected rounding for some results given numpy default precision is meant to be 8.
// "e.g. 0.296140194 -> '0.2961402' not '0.29614019'. ORT produces the latter with precision set to 8,
// which doesn't match the expected output that was generated with numpy.
{"cast_FLOAT_to_STRING", "Numpy float to string has unexpected rounding for some results."},
{"tf_nasnet_large", "disable temporarily"},
{"tf_nasnet_mobile", "disable temporarily"},
{"tf_pnasnet_large", "disable temporarily"},
{"shrink", "test case is wrong", {"onnx141"}},
{"maxpool_with_argmax_2d_precomputed_strides", "ShapeInferenceError"},
{"tf_inception_v2", "result mismatch"},
{"tf_resnet_v1_50", "result mismatch when Conv BN Fusion is applied"},
{"tf_resnet_v1_101", "result mismatch when Conv BN Fusion is applied"},
{"tf_resnet_v1_152", "result mismatch when Conv BN Fusion is applied"},
{"mxnet_arcface", "Model is an invalid ONNX model"},
{"unique_not_sorted_without_axis", "Expected data for 'Y' is incorrect and in sorted order."},
{"cumsum_1d_reverse_exclusive", "only failing linux GPU CI. Likely build error."},
{"resize_downsample_scales_cubic_align_corners", "results mismatch with onnx tests"},
{"resize_downsample_scales_linear_align_corners", "results mismatch with onnx tests"},
{"resize_tf_crop_and_resize", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_ceil_half_pixel", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_floor_align_corners", "Bad onnx test output. Needs test fix."},
{"resize_upsample_sizes_nearest_round_prefer_ceil_asymmetric", "Bad onnx test output. Needs test fix."},
{"bitshift_right_uint16", "BitShift(11) uint16 support not enabled currently"},
{"bitshift_left_uint16", "BitShift(11) uint16 support not enabled currently"},
{"maxunpool_export_with_output_shape", "Invalid output in ONNX test. See https://github.com/onnx/onnx/issues/2398"},
{"training_dropout", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_default", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_default_mask", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"training_dropout_mask", "result differs", {}}, // Temporary, subsequent PR will remove this.
{"adagrad", "not a registered function/op", {}}, // Op not registered.
{"adagrad_multiple", "not a registered function/op", {}}, // Op not registered.
{"adam", "not a registered function/op", {}}, // Op not registered.
{"adam_multiple", "not a registered function/op", {}}, // Op not registered.
{"gradient_of_add", "not a registered function/op", {}}, // Op not registered.
{"gradient_of_add_and_mul", "not a registered function/op", {}}, // Op not registered.
{"momentum", "not a registered function/op", {}}, // Op not registered.
{"momentum_multiple", "not a registered function/op", {}}, // Op not registered.
{"nesterov_momentum", "not a registered function/op", {}}, // Op not registered.
{"sequence_insert_at_back", "onnx currently not supporting loading segment", {}},
{"sequence_insert_at_front", "onnx currently not supporting loading segment", {}},
{"loop13_seq", "ORT api does not currently support creating empty sequences (needed for this test)", {}},
{"cast_FLOAT_to_BFLOAT16", "onnx generate bfloat tensor as uint16 type", {}},
{"cast_BFLOAT16_to_FLOAT", "onnx generate bfloat tensor as uint16 type", {}},
{"castlike_FLOAT_to_BFLOAT16", "Depends on cast.", {}},
{"castlike_BFLOAT16_to_FLOAT", "Depends on cast", {}},
{"castlike_FLOAT_to_BFLOAT16_expanded", "Depends on cast.", {}},
{"castlike_BFLOAT16_to_FLOAT_expanded", "Depends on cast", {}},
{"castlike_FLOAT_to_STRING", "Numpy float to string has unexpected rounding for some results.", {}},
{"castlike_FLOAT_to_STRING_expanded", "Numpy float to string has unexpected rounding for some results.", {}},
{"bernoulli", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_double", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_double_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_seed", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_seed_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"bernoulli_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."},
{"test_roialign_aligned_true", "Opset 16 not supported yet."},
{"test_roialign_aligned_false", "Opset 16 not supported yet."},
{"test_scatternd_add", "Opset 16 not supported yet."},
{"test_scatternd_multiply", "Opset 16 not supported yet."},
{"test_scatter_elements_with_duplicate_indices", "Opset 16 not supported yet."},
#if defined(DISABLE_OPTIONAL_TYPE)
{"test_optional_get_element", "Optional type not supported in this build flavor."},
{"test_optional_get_element_sequence", "Optional type not supported in this build flavor."},
{"test_optional_has_element", "Optional type not supported in this build flavor."},
{"test_optional_has_element_empty", "Optional type not supported in this build flavor."},
{"test_if_opt", "Optional type not supported in this build flavor."},
{"test_loop16_seq_none", "Optional type not supported in this build flavor."},
{"test_identity_opt", "Optional type not supported in this build flavor."},
#endif
};
#ifdef DISABLE_ML_OPS

View file

@ -472,6 +472,7 @@ TEST(If, TestIfWithSequencesAsOutput) {
test.Run();
}
#if !defined(DISABLE_OPTIONAL_TYPE)
// This is to test an "If" node with just an "Identity" node in the "then" and "else" conditional branches
class IfOpTesterWithOptionalTypeAsOutput : public OpTester {
public:
@ -588,5 +589,7 @@ TEST(If, TestIfWithOptionalTypeTensorAsOutput) {
}
}
#endif
} // namespace test
} // namespace onnxruntime

View file

@ -1162,6 +1162,8 @@ TEST(Loop, SequenceAsLoopCarriedDependency) {
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
}
#if !defined(DISABLE_OPTIONAL_TYPE)
TEST(Loop, OptionalTypeAsLoopCarriedDependency) {
auto create_subgraph = [](bool is_optional_tensor_type) {
std::unordered_map<std::string, int> domain_to_version;
@ -1334,5 +1336,7 @@ TEST(Loop, OptionalTypeAsLoopCarriedDependency) {
}
}
#endif
} // namespace test
} // namespace onnxruntime

View file

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#if !defined(DISABLE_OPTIONAL_TYPE)
#include "gtest/gtest.h"
#include "test/providers/provider_test_utils.h"
@ -244,3 +246,5 @@ TEST(OptionalOpTest, OptionalOpsValidateOrtValueReUseForOptionalTensorSequence)
}
} // namespace test
} // namespace onnxruntime
#endif

View file

@ -33,6 +33,8 @@ TEST(Identity, SequenceType) {
test.Run();
}
#if !defined(DISABLE_OPTIONAL_TYPE)
TEST(Identity, OptionalTensorType_NonNone) {
OpTester test("Identity", 16, kOnnxDomain);
// Since this test is being written at a time when only opset 15 has been released, we set
@ -81,5 +83,8 @@ TEST(Identity, OptionalTensorSequenceType_None) {
test.AddOptionalTypeSeqOutput<float>("Y", nullptr); // None
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: opset 16 is not supported yet
}
#endif
} // namespace test
} // namespace onnxruntime

View file

@ -174,6 +174,10 @@ TEST(KernelDefHashTest, ExpectedCpuKernelDefHashes) {
#if defined(ENABLE_TRAINING_OPS)
AppendKernelDefHashesFromFile(ORT_TSTR("testdata/kernel_def_hashes/training_ops.cpu.json"), result);
#endif // ENABLE_TRAINING_OPS
#if !defined(DISABLE_OPTIONAL_TYPE)
AppendKernelDefHashesFromFile(ORT_TSTR("testdata/kernel_def_hashes/onnx.optional_type_ops.cpu.json"), result);
#endif // !DISABLE_OPTIONAL_TYPE
// TODO also handle kernels enabled by these symbols: BUILD_MS_EXPERIMENTAL_OPS
std::sort(result.begin(), result.end());
return result;

View file

@ -225,6 +225,8 @@ struct SequenceTensorType {
template <typename ElemType>
const SequenceTensorTypeProto<ElemType> SequenceTensorType<ElemType>::s_sequence_tensor_type_proto;
#if !defined(DISABLE_OPTIONAL_TYPE)
template <typename ElemType>
struct OptionalTypeProto {
OptionalTypeProto(const ONNX_NAMESPACE::TypeProto& type_proto) {
@ -233,6 +235,8 @@ struct OptionalTypeProto {
ONNX_NAMESPACE::TypeProto proto;
};
#endif
struct CheckParams {
bool sort_output_ = false;
optional<float> absolute_error_;
@ -442,6 +446,8 @@ class OpTester {
AddSeqData<T>(output_data_, name, &seq_tensors);
}
#if !defined(DISABLE_OPTIONAL_TYPE)
template <typename T>
void AddOptionalTypeTensorInput(const char* name, const std::vector<int64_t>& dims,
const std::initializer_list<T>* values = nullptr,
@ -471,6 +477,8 @@ class OpTester {
AddSeqData<T>(output_data_, name, seq_tensors, true);
}
#endif
template <typename TKey, typename TVal>
void AddInput(const char* name, const std::map<TKey, TVal>& val) {
std::unique_ptr<std::map<TKey, TVal>> ptr = std::make_unique<std::map<TKey, TVal>>(val);
@ -826,6 +834,12 @@ class OpTester {
int64_t values_count, bool is_initializer = false, bool sort_output = false,
const std::vector<std::string>* dim_params = nullptr,
float rel_error = 0.0f, float abs_error = 0.0f, bool is_optional_type_tensor = false) {
#if defined(DISABLE_OPTIONAL_TYPE)
if (is_optional_type_tensor) {
ORT_THROW("Optional type is not supported in this build");
}
#endif
ORT_TRY {
TensorShape shape{dims};
@ -861,8 +875,13 @@ class OpTester {
std::vector<int64_t> dims_for_proto = GetDimsForProto(dims);
TTypeProto<T> tensor_type_proto(add_shape_to_tensor_data_ ? &dims_for_proto : nullptr);
#if !defined(DISABLE_OPTIONAL_TYPE)
OptionalTypeProto<T> optional_type_proto(tensor_type_proto.proto);
auto node_arg = NodeArg(name, !is_optional_type_tensor ? &tensor_type_proto.proto : &optional_type_proto.proto);
#else
auto node_arg = NodeArg(name, &tensor_type_proto.proto);
#endif
AddShapeToTensorData(node_arg, dims, dim_params);
@ -897,6 +916,12 @@ class OpTester {
void AddSeqData(std::vector<Data>& data, const char* name,
const SeqTensors<T>* seq_tensors,
bool is_optional_sequence_tensor_type = false) {
#if defined(DISABLE_OPTIONAL_TYPE)
if (is_optional_sequence_tensor_type) {
ORT_THROW("Optional type is not supported in this build");
}
#endif
std::unique_ptr<TensorSeq> ptr;
if (seq_tensors) {
@ -934,14 +959,16 @@ class OpTester {
value.Init(ptr ? ptr.release() : nullptr, mltype, mltype->GetDeleteFunc());
SequenceTensorTypeProto<T> sequence_tensor_proto;
#if !defined(DISABLE_OPTIONAL_TYPE)
OptionalTypeProto<T> optional_type_proto(sequence_tensor_proto.proto);
auto node_arg = NodeArg(name, !is_optional_sequence_tensor_type
? &sequence_tensor_proto.proto
: &optional_type_proto.proto);
#else
auto node_arg = NodeArg(name, &sequence_tensor_proto.proto);
#endif
data.push_back(
Data(NodeArg(name, !is_optional_sequence_tensor_type
? &sequence_tensor_proto.proto
: &optional_type_proto.proto),
std::move(value),
optional<float>(), optional<float>()));
data.push_back(Data(std::move(node_arg), std::move(value), optional<float>(), optional<float>()));
}
std::vector<int64_t> GetDimsForProto(gsl::span<const int64_t> dims);

View file

@ -1475,18 +1475,6 @@
"OneHot ai.onnx CPUExecutionProvider",
15162687909384154912
],
[
"Optional ai.onnx CPUExecutionProvider",
4007199385789893408
],
[
"OptionalGetElement ai.onnx CPUExecutionProvider",
8727767224223660008
],
[
"OptionalHasElement ai.onnx CPUExecutionProvider",
103583056104706000
],
[
"Or ai.onnx CPUExecutionProvider",
18295541712828245416

View file

@ -0,0 +1,14 @@
[
[
"Optional ai.onnx CPUExecutionProvider",
4007199385789893408
],
[
"OptionalGetElement ai.onnx CPUExecutionProvider",
8727767224223660008
],
[
"OptionalHasElement ai.onnx CPUExecutionProvider",
103583056104706000
]
]

View file

@ -72,10 +72,13 @@
// Uncomment here once the ONNX backend test runner is able to handle
// optional type test data.
// https://github.com/onnx/onnx/issues/3608
// TODO: Once ONNX #3608 is solved and these tests are removed from exclusion,
// we need to figure out a way to keep these tests in the exclusion list for
// builds that have disabled support for the optional type.
"^test_optional_*",
"^test_if_opt",
"^test_loop16_seq_none",
"^test_identity",
"^test_identity_opt",
// Following tests are for opset 16 ops and are not yet implemented in ORT
"^test_roialign_aligned_*",
"^test_scatternd_*",