Skip to content

Commit

Permalink
[CPU] IsFinite, IsInf and IsNaN operations JIT implementation. (#14697)
Browse files Browse the repository at this point in the history
  • Loading branch information
nshchego authored Dec 29, 2022
1 parent 36a16c8 commit 24f1a92
Show file tree
Hide file tree
Showing 6 changed files with 732 additions and 421 deletions.
916 changes: 549 additions & 367 deletions src/plugins/intel_cpu/src/emitters/jit_eltwise_emitters.cpp

Large diffs are not rendered by default.

141 changes: 111 additions & 30 deletions src/plugins/intel_cpu/src/emitters/jit_eltwise_emitters.hpp

Large diffs are not rendered by default.

19 changes: 15 additions & 4 deletions src/plugins/intel_cpu/src/nodes/eltwise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ struct EltwiseEmitter<jit_power_static_emitter> {
}
};

template<>
struct EltwiseEmitter<jit_is_inf_emitter> {
void operator()(EltwiseEmitterContext & ctx) {
ctx.emitter = std::make_shared<jit_is_inf_emitter>(ctx.host, ctx.host_isa, ctx.exec_prc, ctx.opData.alpha, ctx.opData.beta);
}
};

/**
* Implements Eltwise shape inference algorithm. The algorithm is based on broadcasting all the input shapes
* according to the NUMPY broadcast rule. This implementation is more lightweight than the ngraph one.
Expand Down Expand Up @@ -518,7 +525,10 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
OV_CASE(Algorithm::EltwisePowerStatic, jit_power_static_emitter),
OV_CASE(Algorithm::EltwisePrelu, jit_prelu_emitter),
OV_CASE(Algorithm::EltwiseErf, jit_erf_emitter),
OV_CASE(Algorithm::EltwiseSoftSign, jit_soft_sign_emitter));
OV_CASE(Algorithm::EltwiseSoftSign, jit_soft_sign_emitter),
OV_CASE(Algorithm::EltwiseIsFinite, jit_is_finite_emitter),
OV_CASE(Algorithm::EltwiseIsInf, jit_is_inf_emitter),
OV_CASE(Algorithm::EltwiseIsNaN, jit_is_nan_emitter));

if (precisions.empty())
IE_THROW() << "Unsupported operation type for Eltwise emitter";
Expand Down Expand Up @@ -576,7 +586,10 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
OV_CASE(Algorithm::EltwisePowerStatic, jit_power_static_emitter),
OV_CASE(Algorithm::EltwisePrelu, jit_prelu_emitter),
OV_CASE(Algorithm::EltwiseErf, jit_erf_emitter),
OV_CASE(Algorithm::EltwiseSoftSign, jit_soft_sign_emitter));
OV_CASE(Algorithm::EltwiseSoftSign, jit_soft_sign_emitter),
OV_CASE(Algorithm::EltwiseIsFinite, jit_is_finite_emitter),
OV_CASE(Algorithm::EltwiseIsInf, jit_is_inf_emitter),
OV_CASE(Algorithm::EltwiseIsNaN, jit_is_nan_emitter));

if (!ctx.emitter)
IE_THROW() << "Unsupported operation type for Eltwise emitter";
Expand Down Expand Up @@ -1750,8 +1763,6 @@ void Eltwise::initSupportedPrimitiveDescriptors() {

// if dim rank is greater than the maximum possible, we should use the reference execution
canUseOptimizedImpl = mayiuse(x64::sse41) && getInputShapeAtPort(0).getRank() <= MAX_ELTWISE_DIM_RANK;
// 98206 to add JIT implementation.
canUseOptimizedImpl &= !one_of(getAlgorithm(), Algorithm::EltwiseIsFinite, Algorithm::EltwiseIsInf, Algorithm::EltwiseIsNaN);

if (!canUseOptimizedImpl && !fusedWith.empty()) {
IE_THROW(Unexpected) << "Eltwise node with name '" << getName() << "' uses reference impl, but unexpectedly fused with other ops";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,31 @@ const auto ComparisonTestParams = ::testing::Combine(

INSTANTIATE_TEST_SUITE_P(smoke_CompareWithRefs, ComparisonLayerTest, ComparisonTestParams, ComparisonLayerTest::getTestCaseName);


std::vector<InputShapesTuple> inputShapesIsOps = {
{{1}, {1}},
{{1, 2}, {1}},
{{3, 1}, {1}},
{{2, 2}, {1}},
{{1, 5, 1}, {1}},
{{2, 1, 1, 3, 1}, {1}},
{{7, 1, 1, 1, 1}, {1}},
{{2, 2, 2}, {1}},
{{3, 1, 3, 3}, {1}},
{{17}, {1}},
{{2, 18}, {1}},
{{1, 3, 20}, {1}},
{{2, 200}, {1}},
{{2, 17, 3, 4}, {1}}
};

std::vector<ngraph::helpers::ComparisonTypes> comparisonOpTypesIs = {
ngraph::helpers::ComparisonTypes::IS_FINITE,
ngraph::helpers::ComparisonTypes::IS_INF,
ngraph::helpers::ComparisonTypes::IS_NAN
};

const auto ComparisonTestParamsIs = ::testing::Combine(
::testing::ValuesIn(CommonTestUtils::combineParams(inputShapes)),
::testing::ValuesIn(inputShapesIsOps),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::ValuesIn(comparisonOpTypesIs),
::testing::Values(ngraph::helpers::InputLayerType::CONSTANT),
Expand All @@ -73,4 +90,4 @@ const auto ComparisonTestParamsIs = ::testing::Combine(

INSTANTIATE_TEST_SUITE_P(smoke_IsOp, ComparisonLayerTest, ComparisonTestParamsIs, ComparisonLayerTest::getTestCaseName);

} // namespace
} // namespace
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,34 @@ void ComparisonLayerTest::SetUp() {
}

InferenceEngine::Blob::Ptr ComparisonLayerTest::GenerateInput(const InferenceEngine::InputInfo &inputInfo) const {
auto blob = LayerTestsUtils::LayerTestsCommon::GenerateInput(inputInfo);
InferenceEngine::Blob::Ptr blob;

if (comparisonOpType == ComparisonTypes::IS_FINITE || comparisonOpType == ComparisonTypes::IS_NAN) {
auto *dataPtr = blob->buffer().as<float*>();
auto range = blob->size();
blob = make_blob_with_precision(inputInfo.getTensorDesc());
blob->allocate();
auto dataPtr = blob->buffer().as<float*>();
auto dataPtrInt = blob->buffer().as<int*>();
const auto range = blob->size();
const float start = -static_cast<float>(range) / 2.f;
testing::internal::Random random(1);

if (comparisonOpType == ComparisonTypes::IS_FINITE) {
for (size_t i = 0; i < range / 2; i++) {
dataPtr[random.Generate(range)] =
i % 3 == 0 ? std::numeric_limits<float>::infinity() : i % 3 == 1 ? -std::numeric_limits<float>::infinity() :
std::numeric_limits<double>::quiet_NaN();
}
} else {
for (size_t i = 0; i < range / 2; i++) {
dataPtr[random.Generate(range)] = std::numeric_limits<double>::quiet_NaN();
for (size_t i = 0; i < range; i++) {
if (i % 7 == 0) {
dataPtr[i] = std::numeric_limits<float>::infinity();
} else if (i % 7 == 1) {
dataPtr[i] = -std::numeric_limits<float>::infinity();
} else if (i % 7 == 2) {
dataPtrInt[i] = 0x7F800000 + random.Generate(range);
} else if (i % 7 == 3) {
dataPtr[i] = std::numeric_limits<double>::quiet_NaN();
} else if (i % 7 == 5) {
dataPtr[i] = -std::numeric_limits<double>::quiet_NaN();
} else {
dataPtr[i] = start + static_cast<float>(random.Generate(range));
}
}
} else {
blob = LayerTestsUtils::LayerTestsCommon::GenerateInput(inputInfo);
}

return blob;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,25 @@ void IsInfLayerTest::generate_inputs(const std::vector<ov::Shape>& targetInputSt
const auto& funcInputs = function->inputs();
const auto& input = funcInputs[0];

int32_t range = std::accumulate(targetInputStaticShapes[0].begin(), targetInputStaticShapes[0].end(), 1u, std::multiplies<uint32_t>());
auto tensor = utils::create_and_fill_tensor(
input.get_element_type(), targetInputStaticShapes[0], range, -range / 2, 1);
int32_t range = std::accumulate(targetInputStaticShapes[0].begin(), targetInputStaticShapes[0].end(), 1, std::multiplies<uint32_t>());
float startFrom = -static_cast<float>(range) / 2.f;
auto tensor = ov::Tensor{ input.get_element_type(), targetInputStaticShapes[0]};

auto pointer = tensor.data<element_type_traits<ov::element::Type_t::f32>::value_type>();
testing::internal::Random random(1);

for (size_t i = 0; i < range / 2; i++) {
pointer[random.Generate(range)] = i % 2 == 0 ? std::numeric_limits<float>::infinity() : -std::numeric_limits<float>::infinity();
for (size_t i = 0; i < range; i++) {
if (i % 7 == 0) {
pointer[i] = std::numeric_limits<float>::infinity();
} else if (i % 7 == 1) {
pointer[i] = std::numeric_limits<double>::quiet_NaN();
} else if (i % 7 == 3) {
pointer[i] = -std::numeric_limits<float>::infinity();
} else if (i % 7 == 5) {
pointer[i] = -std::numeric_limits<double>::quiet_NaN();
} else {
pointer[i] = startFrom + static_cast<float>(random.Generate(range));
}
}

inputs.insert({input.get_node_shared_ptr(), tensor});
Expand Down

0 comments on commit 24f1a92

Please sign in to comment.