Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion onnxruntime/contrib_ops/cpu/image_scaler.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ class ImageScaler final : public OpKernel {
const int64_t H = dims[2];
const int64_t W = dims[3];

if (!bias_.empty() && bias_.size() != static_cast<size_t>(C)) {
// The loop below reads bias_[nc % C] for every channel, so the bias must have exactly one entry
// per channel. An empty bias is not a valid "no bias" state here: the constructor already fails
// when the attribute is absent, and a present-but-empty attribute would otherwise index an
// empty vector.
if (bias_.size() != static_cast<size_t>(C)) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Bias size (", bias_.size(), ") does not match the number of channels (", C, ")");
}

Expand Down
4 changes: 3 additions & 1 deletion onnxruntime/contrib_ops/cuda/tensor/image_scaler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ Status ImageScaler<T>::ComputeInternal(OpKernelContext* context) const {

const int64_t C = dims[1]; // dims are NCHW

if (!bias_.empty() && bias_.size() != static_cast<size_t>(C)) {
// The kernel indexes bias_data[c] for every channel, so the bias must have exactly one entry per
// channel. An empty bias would leave b_data_ pointing at a zero-sized allocation.
if (bias_.size() != static_cast<size_t>(C)) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Bias size (", bias_.size(), ") does not match the number of channels (", C, ")");
}

Expand Down
25 changes: 25 additions & 0 deletions onnxruntime/test/contrib_ops/tensor_op_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,31 @@ TEST(ImageScalerContribOpTest, ImageScalerTest) {
test.Run();
}

TEST(ImageScalerContribOpTest, ImageScalerEmptyBias) {
if (DefaultDmlExecutionProvider().get() != nullptr) {
GTEST_SKIP() << "Skipping because of the following error: AbiCustomRegistry.cpp(507): The parameter is incorrect.";
}

constexpr int64_t N = 1, C = 2, H = 2, W = 2;
std::vector<float> X = {
1.0f, 3.0f,
3.0f, 5.0f,

3.0f, 5.0f,
7.0f, 9.0f};

// A present-but-empty bias supplies no value for any channel and must be rejected rather than
// indexing an empty vector.
OpTester test("ImageScaler");
test.AddAttribute("scale", 2.0f);
test.AddAttribute("bias", std::vector<float>{});
test.AddInput<float>("input", {N, C, H, W}, X);
test.AddOutput<float>("output", {N, C, H, W}, std::vector<float>(N * C * H * W, 0.0f));
test.Run(OpTester::ExpectResult::kExpectFailure,
"Bias size (0) does not match the number of channels (2)",
{kTensorrtExecutionProvider});
}

void MeanVarianceNormalizationAcrossChannels(bool across_channels, bool normalize_variance) {
constexpr int64_t N = 2, C = 2, H = 2, W = 3;
constexpr int64_t one = 1;
Expand Down
Loading