onnxruntime/onnxruntime/test/common/random_generator_test.cc
Wei-Sheng Chin 1524f73a09
Implement two easier random tensor generator (RTG) for flaky tests (#15517)
Some math ops have very bad numerical stability and essential randomness
(e.g., exp/log with reduction on large elements). To maintain the same
test coverage with lower CI failing rate, we can gradually replace flaky
tests' RTG with the ones implemented in this PR --- try Discrete first.
If still unstable, use Circular.

Overall recommended strategy to handle flaky test
- Find if it uses `Uniform` in
`onnxruntime/test/common/tensor_op_test_utils.h`. If yes, replace
`Uniform` with `Discrete` implemented in this PR. For
`candidate_values`, we can try `[-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5,
2]`, `[-2, -1, 0, 1, 2]`, `[-1, 0, 1]`, and `[0, 1]` and choose the most
difficult one among those passing 100 runs.
- If `Discrete` fails to meet the stability requirement, switch to
`Circular` and repeat the `candidate_values` selection process.

Let's keep an eye on the two bugs mentioned in
https://github.com/microsoft/onnxruntime/pull/15515. If the related unit
tests fail again, we can replace the underlying
`RandomValueGenerator::Uniform` with
`FixedPatternValueGenerator::Descrete` or
`FixedPatternValueGenerator::Circular` implemented in this PR.
2023-04-25 17:52:44 -07:00

77 lines
2.2 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "gtest/gtest.h"
#include "test/common/tensor_op_test_utils.h"
#include <vector>
namespace onnxruntime {
namespace test {
TEST(TensorGenerator, DiscreteFloat) {
FixedPatternValueGenerator random{};
const std::vector<int64_t> shape = {2, 3};
std::vector<float> data = random.Discrete<float>(shape, {-1.f, 0.f, 1.f});
ASSERT_EQ(data.size(), static_cast<size_t>(6));
for (float value : data) {
EXPECT_TRUE(value == -1.f || value == 0.f || value == 1.f);
}
}
TEST(TensorGenerator, DiscreteInt) {
FixedPatternValueGenerator random{};
const std::vector<int64_t> shape = {2, 3};
std::vector<int> data = random.Discrete<int>(shape, {-1, 0, 1});
ASSERT_EQ(data.size(), static_cast<size_t>(6));
for (int value : data) {
EXPECT_TRUE(value == -1 || value == 0 || value == 1);
}
}
// Tests for Circular
TEST(TensorGenerator, CircularFloat) {
FixedPatternValueGenerator random{};
const std::vector<int64_t> shape = {3, 2};
std::vector<float> data = random.Circular<float>(shape, {-1.f, 0.f, 1.f});
ASSERT_EQ(data.size(), static_cast<size_t>(6));
EXPECT_EQ(data[0], -1.f);
EXPECT_EQ(data[1], 0.f);
EXPECT_EQ(data[2], 1.f);
EXPECT_EQ(data[3], -1.f);
EXPECT_EQ(data[4], 0.f);
EXPECT_EQ(data[5], 1.f);
}
TEST(TensorGenerator, CircularInt) {
FixedPatternValueGenerator random{};
const std::vector<int64_t> shape = {3, 2};
std::vector<int> data = random.Circular<int>(shape, {-1, 0, 1});
ASSERT_EQ(data.size(), static_cast<size_t>(6));
EXPECT_EQ(data[0], -1);
EXPECT_EQ(data[1], 0);
EXPECT_EQ(data[2], 1);
EXPECT_EQ(data[3], -1);
EXPECT_EQ(data[4], 0);
EXPECT_EQ(data[5], 1);
}
TEST(TensorGenerator, CircularBool) {
FixedPatternValueGenerator random{};
const std::vector<int64_t> shape = {3, 2};
std::vector<bool> data = random.Circular<bool>(shape, {false, true});
ASSERT_EQ(data.size(), static_cast<size_t>(6));
EXPECT_EQ(data[0], false);
EXPECT_EQ(data[1], true);
EXPECT_EQ(data[2], false);
EXPECT_EQ(data[3], true);
EXPECT_EQ(data[4], false);
EXPECT_EQ(data[5], true);
}
} // namespace test
} // namespace onnxruntime