Repository: microsoft/onnxruntime
File: onnxruntime/core/providers/qnn/builder/opbuilder/base_op_builder.cc (C++)

Code before:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/providers/qnn/builder/opbuilder/base_op_builder.h"
#include <utility>
#include "core/providers/qnn/builder/qnn_utils.h"

namespace onnxruntime {
namespace qnn {

namespace {
bool IsOptionalNodeUnitIODef(const NodeUnitIODef& node_io_def) {
  const NodeArg& arg = node_io_def.node_arg;
  return !arg.Exists() || arg.Name().empty();
}

// Function to check whether we should skip processing null input which has 0 dim in shape.
// Such null inputs often exist in models saved from PyTorch, especially for Concat.
bool IsNullNodeUnitIODef(QnnModelWrapper& qnn_model_wrapper,
                         const NodeUnit& node_unit,
                         const NodeUnitIODef& node_io_def,
                         const logging::Logger& logger) {
  // Although the 0 dim issue should be handled for all op types, restricting in Concat for now since current cases
  // only happen on one of Concat inputs.
  if (node_unit.OpType() != "Concat") {
    return false;
  }

  std::vector<uint32_t> input_shape;
  if (!qnn_model_wrapper.GetOnnxShape(node_io_def.node_arg, input_shape)) {
    return false;
  }

  for (const uint32_t& dim : input_shape) {
    if (dim == 0) {
      LOGS(logger, WARNING) << "Tensor has 0 dim, ignore this input: " << node_io_def.node_arg.Name();
      return true;
    }
  }

  return false;
}
}  // namespace


Review comment (refactor):
it's not obvious to me what "null node unit I/O def" means. looking at the code, it is checking if any dimensions are zero. can the name be made clearer?

for example, here's a shape-related helper which does the same thing:
https://github.com/microsoft/onnxruntime/blob/db6d83b615d06eb8e4c777385085006a13f1322e/onnxruntime/core/providers/coreml/shape_utils.cc#L56-L58

also, the check for `node_unit.OpType() != "Concat"` feels out of place in a function with a more general name.

Code after:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/providers/qnn/builder/opbuilder/base_op_builder.h"
#include <utility>
#include "core/providers/qnn/builder/qnn_utils.h"

namespace onnxruntime {
namespace qnn {

namespace {
bool IsOptionalNodeUnitIODef(const NodeUnitIODef& node_io_def) {
  const NodeArg& arg = node_io_def.node_arg;
  return !arg.Exists() || arg.Name().empty();
}

// Function to check whether we should skip processing null input which has 0 dim in shape.
// Such null inputs often exist in models saved from PyTorch, especially for Concat.
bool DoesConcatInputShapeContainZero(QnnModelWrapper& qnn_model_wrapper,
                                     const NodeUnit& node_unit,
                                     const NodeUnitIODef& node_io_def,
                                     const logging::Logger& logger) {
  // Although the 0 dim issue should be handled for all op types, restricting in Concat for now since current cases
  // only happen on one of Concat inputs. One may rename the function and relax the checking here to extend for other
  // ops.
  if (node_unit.OpType() != "Concat") {
    return false;
  }

  std::vector<uint32_t> input_shape;
  if (!qnn_model_wrapper.GetOnnxShape(node_io_def.node_arg, input_shape)) {
    return false;
  }

  for (const uint32_t& dim : input_shape) {
    if (dim == 0) {
      LOGS(logger, WARNING) << "Tensor has 0 dim, ignore this input: " << node_io_def.node_arg.Name();
      return true;
    }
  }

  return false;
}
}  // namespace