Skip to content
Merged
1 change: 0 additions & 1 deletion include/onnxruntime/core/graph/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,6 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi
cannot be overridden at runtime. If the initializer is not found or is not constant, a nullptr is returned.
@param check_outer_scope If true and the graph is a subgraph,
check ancestor graph/s for 'name' if not found in 'graph'.
@remarks check_outer_scope of true is not supported in a minimal build
*/
const ONNX_NAMESPACE::TensorProto* GetConstantInitializer(const std::string& name, bool check_outer_scope) const;

Expand Down
3 changes: 2 additions & 1 deletion include/onnxruntime/core/graph/graph_viewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ class GraphViewer {
if a const initializer is part of the underlying Graph but not part of this GraphViewer,
it will still be returned instead of nullptr
*/
const ONNX_NAMESPACE::TensorProto* GetConstantInitializer(const std::string& name, bool check_outer_scope) const;
const ONNX_NAMESPACE::TensorProto* GetConstantInitializer(const std::string& name,
bool check_outer_scope = true) const;

/** Get the Node containing this Graph if IsSubgraph is true. Returns nullptr otherwise. */
const Node* ParentNode() const noexcept { return graph_->ParentNode(); }
Expand Down
2 changes: 2 additions & 0 deletions onnxruntime/core/graph/graph_viewer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ const std::string& GraphViewer::Description() const noexcept {

bool GraphViewer::GetInitializedTensor(const std::string& tensor_name,
const ONNX_NAMESPACE::TensorProto*& value) const {
value = nullptr;

// if we are using filtered subgraph, the initializer has to be part of the subgraph
if (filter_info_ != nullptr && filtered_initializers_.find(tensor_name) == filtered_initializers_.cend())
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Status ClipOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder,
const auto& input_name = node.InputDefs()[0]->Name();
const auto& output_name = node.OutputDefs()[0]->Name();
float min, max;
ORT_RETURN_IF_NOT(GetClipMinMax(model_builder.GetInitializerTensors(), node, min, max, logger), "GetClipMinMax failed");
ORT_RETURN_IF_NOT(GetClipMinMax(model_builder.GetGraphViewer(), node, min, max, logger), "GetClipMinMax failed");

bool has_min = min != std::numeric_limits<float>::lowest();
bool has_max = max != std::numeric_limits<float>::max();
Expand Down Expand Up @@ -132,8 +132,7 @@ Status ClipOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder,
bool ClipOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params,
const logging::Logger& logger) const {
float min, max;
const auto& initializers = input_params.graph_viewer.GetAllInitializedTensors();
return GetClipMinMax(initializers, node, min, max, logger);
return GetClipMinMax(input_params.graph_viewer, node, min, max, logger);
}

void CreateClipOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) {
Expand Down
37 changes: 23 additions & 14 deletions onnxruntime/core/providers/nnapi/nnapi_builtin/builders/helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,8 @@ bool HasValidBinaryOpQuantizedInputTypes(const NodeUnit& node_unit) {
return true;
}

common::Status GetQuantizationScaleAndZeroPoint(
const InitializedTensorSet& initializers, const NodeUnitIODef& io_def, const Path& model_path,
float& scale, int32_t& zero_point) {
common::Status GetQuantizationScaleAndZeroPoint(const GraphViewer& graph_viewer, const NodeUnitIODef& io_def,
const Path& model_path, float& scale, int32_t& zero_point) {
scale = 0.0f;
zero_point = 0;

Expand All @@ -198,28 +197,38 @@ common::Status GetQuantizationScaleAndZeroPoint(
const auto& quant_param = *io_def.quant_param;
{ // get the scale
const auto& name = quant_param.scale.Name();
Initializer unpacked_tensor(*initializers.at(name), model_path);
const auto* s = graph_viewer.GetConstantInitializer(name);
if (!s) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, name, " is not a constant initializer");
};

Initializer unpacked_tensor(*s, model_path);
// The scale should be one or more floats
scale = unpacked_tensor.DataAsSpan<float>()[0];
}

if (quant_param.zero_point) { // get the zero point if it's there
const auto& name = quant_param.zero_point->Name();
Initializer unpacked_tensor(*initializers.at(name), model_path);
const auto* zp = graph_viewer.GetConstantInitializer(name);
if (!zp) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, name, " is not a constant initializer");
};

Initializer unpacked_tensor(*zp, model_path);
// Onnx quantization uses uint8 [int8 not yet supported], need to cast to int32_t used by NNAPI
zero_point = static_cast<int32_t>(unpacked_tensor.DataAsByteSpan()[0]);
}

return Status::OK();
}

common::Status GetQuantizationScaleAndZeroPoint(
const InitializedTensorSet& initializers, const NodeUnit& node_unit, const std::string& name,
float& scale, int32_t& zero_point, ArgType arg_type) {
common::Status GetQuantizationScaleAndZeroPoint(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const std::string& name, float& scale, int32_t& zero_point,
ArgType arg_type) {
const auto& io_defs = arg_type == ArgType::kInput ? node_unit.Inputs() : node_unit.Outputs();
for (const auto& io_def : io_defs) {
if (io_def.node_arg.Name() == name)
return GetQuantizationScaleAndZeroPoint(initializers, io_def, node_unit.ModelPath(),
return GetQuantizationScaleAndZeroPoint(graph_viewer, io_def, node_unit.ModelPath(),
scale, zero_point);
}

Expand Down Expand Up @@ -348,7 +357,7 @@ bool IsNodeSupported(const NodeUnit& node_unit, const GraphViewer& graph_viewer,
}

const auto* op_builder = op_builder_it->second;
return op_builder->IsOpSupported(graph_viewer.GetAllInitializedTensors(), node_unit, params);
return op_builder->IsOpSupported(graph_viewer, node_unit, params);
}

bool IsNodeSupportedInGroup(const NodeUnit& node_unit, const GraphViewer& graph_viewer,
Expand Down Expand Up @@ -381,11 +390,11 @@ uint32_t ShapeSize(const Shape& shape, size_t begin_idx, size_t end_idx) {
SafeInt<uint32_t>{1}, std::multiplies<SafeInt<uint32_t>>{});
}

bool CheckIsInitializer(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
const std::string& input_name, const char* input_description) {
if (!Contains(initializers, input_name)) {
bool CheckIsConstantInitializer(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const std::string& input_name, const char* input_description) {
if (!graph_viewer.GetConstantInitializer(input_name)) {
LOGS_DEFAULT(VERBOSE) << input_description << " of " << node_unit.Name() << "of type ["
<< node_unit.OpType() << "] must be an initializer tensor";
<< node_unit.OpType() << "] must be a constant initializer";
return false;
}

Expand Down
10 changes: 5 additions & 5 deletions onnxruntime/core/providers/nnapi/nnapi_builtin/builders/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ bool IsQuantizedBinaryOp(QuantizedOpType quant_op_type);
bool HasValidBinaryOpQuantizedInputTypes(const NodeUnit& node_unit);

common::Status GetQuantizationScaleAndZeroPoint(
const InitializedTensorSet& initializers, const NodeUnitIODef& io_def, const Path& model_path,
const GraphViewer& graph_viewer, const NodeUnitIODef& io_def, const Path& model_path,
float& scale, int32_t& zero_point);

common::Status GetQuantizationScaleAndZeroPoint(
const InitializedTensorSet& initializers, const NodeUnit& node_unit, const std::string& name,
const GraphViewer& graph_viewer, const NodeUnit& node_unit, const std::string& name,
float& scale, int32_t& zero_point, ArgType arg_type = ArgType::kInput);

// Get Shape/Type of a NodeArg
Expand Down Expand Up @@ -167,11 +167,11 @@ inline uint32_t ShapeSize(const Shape& shape) {
return ShapeSize(shape, 0, shape.size());
}

// Check the given input is an initializer tensor
// Check the given input is a constant initializer
// input_name is the name of the initializer
// input_description is the string describing the input in the output message (if any)
bool CheckIsInitializer(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
const std::string& input_name, const char* input_description);
bool CheckIsConstantInitializer(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const std::string& input_name, const char* input_description);

// Convert ONNX int64 input to NNAPI int32 type input and optionally handle negative axis if needed
// Mostly used in handling `axes` input for now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class LRNOpBuilder : public BaseOpBuilder {

// Operator support related
private:
bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const override;

int32_t GetMinSupportedNNAPIFeatureLevel(const NodeUnit& /* node_unit */,
Expand Down Expand Up @@ -91,7 +91,7 @@ Status LRNOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const No

// Operator support related

bool LRNOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const NodeUnit& node_unit,
bool LRNOpBuilder::IsOpSupportedImpl(const GraphViewer& /* graph_viewer */, const NodeUnit& node_unit,
const OpSupportCheckParams& /* params */) const {
Shape input_shape;
if (!GetShape(node_unit.Inputs()[0].node_arg, input_shape))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/graph/graph_viewer.h"
#include "core/providers/nnapi/nnapi_builtin/builders/impl/base_op_builder.h"

namespace onnxruntime {
Expand All @@ -11,10 +12,11 @@ bool HasExternalInitializer(const InitializedTensorSet& initializers, const Node
const auto is_ext_initializer =
[&](const NodeArg& node_arg) {
const auto& input_name(node_arg.Name());
if (!Contains(initializers, input_name))
const auto initializer = initializers.find(input_name);
if (initializer == initializers.end())
return false;

const auto& tensor = *initializers.at(input_name);
const auto& tensor = *initializer->second;
if (tensor.has_data_location() &&
tensor.data_location() == ONNX_NAMESPACE::TensorProto_DataLocation_EXTERNAL) {
LOGS_DEFAULT(VERBOSE) << "Initializer [" << input_name
Expand Down Expand Up @@ -51,8 +53,12 @@ Status BaseOpBuilder::AddToModelBuilder(ModelBuilder& model_builder, const NodeU
model_builder.GetEffectiveFeatureLevel(),
model_builder.UseNCHW(),
};
ORT_RETURN_IF_NOT(IsOpSupported(model_builder.GetInitializerTensors(), node_unit, params),
"Unsupported operator ", node_unit.OpType());

// We checked supported in IExecutionProvider::GetCapability.
// Checking again in AddToModelBuilder which is called in IExecutionProvider::Compile is redundant.
// ORT_RETURN_IF_NOT(IsOpSupported(model_builder.GetGraphViewer(), node_unit, params),
// "Unsupported operator ", node_unit.OpType());

#ifndef NDEBUG
model_builder.SetDebugCurrentOnnxNodeIndex(node_unit.Index());
#endif
Expand All @@ -64,7 +70,7 @@ Status BaseOpBuilder::AddToModelBuilder(ModelBuilder& model_builder, const NodeU

// Operator support related

bool BaseOpBuilder::IsOpSupported(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool BaseOpBuilder::IsOpSupported(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const {
int32_t required_feature_level = GetMinSupportedNNAPIFeatureLevel(node_unit, params);
if (required_feature_level > params.android_feature_level) {
Expand All @@ -77,20 +83,20 @@ bool BaseOpBuilder::IsOpSupported(const InitializedTensorSet& initializers, cons
if (!IsNodeUnitTypeSupported(node_unit))
return false;

if (!HasSupportedInputOutputs(initializers, node_unit, params))
if (!HasSupportedInputOutputs(graph_viewer, node_unit, params))
return false;

// We do not support external initializers for now
if (HasExternalInitializer(initializers, node_unit))
if (HasExternalInitializer(graph_viewer.GetAllInitializedTensors(), node_unit))
return false;

if (!HasSupportedOpSet(node_unit))
return false;

return IsOpSupportedImpl(initializers, node_unit, params);
return IsOpSupportedImpl(graph_viewer, node_unit, params);
}

bool BaseOpBuilder::HasSupportedInputOutputs(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool BaseOpBuilder::HasSupportedInputOutputs(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const {
// We do not support unknown(null) input shape
auto has_supported_shape = [](const NodeArg& node_arg, const std::string& name, const std::string& op_type) {
Expand Down Expand Up @@ -128,12 +134,12 @@ bool BaseOpBuilder::HasSupportedInputOutputs(const InitializedTensorSet& initial
return false;
}
}
return HasSupportedInputOutputsImpl(initializers, node_unit, params);

return HasSupportedInputOutputsImpl(graph_viewer, node_unit, params);
}

bool BaseOpBuilder::HasSupportedInputOutputsImpl(
const InitializedTensorSet& /* initializers */, const NodeUnit& node_unit,
const OpSupportCheckParams& /* params */) const {
bool BaseOpBuilder::HasSupportedInputOutputsImpl(const GraphViewer& /* graph_viewer */, const NodeUnit& node_unit,
const OpSupportCheckParams& /* params */) const {
// We only check the type of input 0 by default
// specific op builder can override this
const auto& input = node_unit.Inputs()[0].node_arg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ class BaseOpBuilder : public IOpBuilder {

// Operator support related
public:
bool IsOpSupported(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool IsOpSupported(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const override;

protected:
virtual bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const NodeUnit& /* node_unit */,
virtual bool IsOpSupportedImpl(const GraphViewer& /* graph_viewer */, const NodeUnit& /* node_unit */,
const OpSupportCheckParams& /* params */) const {
return true;
}
Expand All @@ -68,9 +68,8 @@ class BaseOpBuilder : public IOpBuilder {
return ANEURALNETWORKS_FEATURE_LEVEL_1;
}

virtual bool HasSupportedInputOutputsImpl(
const InitializedTensorSet& initializers, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const;
virtual bool HasSupportedInputOutputsImpl(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const;

virtual int GetMinSupportedOpSet(const NodeUnit& /* node_unit */) const { return 1; }
virtual int GetMaxSupportedOpSet(const NodeUnit& /* node_unit */) const { return 19; }
Expand All @@ -82,7 +81,7 @@ class BaseOpBuilder : public IOpBuilder {

private:
bool HasSupportedOpSet(const NodeUnit& node_unit) const;
bool HasSupportedInputOutputs(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool HasSupportedInputOutputs(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class BatchNormalizationOpBuilder : public BaseOpBuilder {

// Operator support related
private:
bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& params) const override;

// BatchNormalization opset 6- has unsupported attributes
Expand Down Expand Up @@ -127,7 +127,7 @@ Status BatchNormalizationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_bu

// Operator support related

bool BatchNormalizationOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const NodeUnit& node_unit,
bool BatchNormalizationOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const NodeUnit& node_unit,
const OpSupportCheckParams& /* params */) const {
if (node_unit.Outputs().size() != 1) {
LOGS_DEFAULT(VERBOSE) << "Your onnx model may be in training mode, please export "
Expand Down Expand Up @@ -158,20 +158,20 @@ bool BatchNormalizationOpBuilder::IsOpSupportedImpl(const InitializedTensorSet&
const auto& b_name = inputs[2].node_arg.Name();
const auto& mean_name = inputs[3].node_arg.Name();
const auto& var_name = inputs[4].node_arg.Name();
if (!Contains(initializers, scale_name)) {
LOGS_DEFAULT(VERBOSE) << "Scale of BN must be known";
if (!graph_viewer.GetConstantInitializer(scale_name)) {
LOGS_DEFAULT(VERBOSE) << "Scale of BN must be a constant initializer";
return false;
}
if (!Contains(initializers, b_name)) {
LOGS_DEFAULT(VERBOSE) << "B of BN must be known";
if (!graph_viewer.GetConstantInitializer(b_name)) {
LOGS_DEFAULT(VERBOSE) << "B of BN must be a constant initializer";
return false;
}
if (!Contains(initializers, mean_name)) {
LOGS_DEFAULT(VERBOSE) << "Mean of BN must be known";
if (!graph_viewer.GetConstantInitializer(mean_name)) {
LOGS_DEFAULT(VERBOSE) << "Mean of BN must be a constant initializer";
return false;
}
if (!Contains(initializers, var_name)) {
LOGS_DEFAULT(VERBOSE) << "Var of BN must be known";
if (!graph_viewer.GetConstantInitializer(var_name)) {
LOGS_DEFAULT(VERBOSE) << "Var of BN must be a constant initializer";
return false;
}

Expand Down
Loading