Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CumSum reference implementation revision #6915

Merged
merged 29 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a533ccd
New CumSum implementation init
mitruska Aug 3, 2021
77d14a1
Unified ndim approach
mitruska Aug 3, 2021
0fa7524
Move transpose to separate function
mitruska Aug 3, 2021
0a2d8ad
Move transpose to original to separate function
mitruska Aug 3, 2021
4fd28e2
Move slice_count calculation to function
mitruska Aug 3, 2021
dc35097
Negative axes support
mitruska Aug 3, 2021
852aa63
Refactor redundant copy
mitruska Aug 3, 2021
98146a3
Changed copy to move
mitruska Aug 3, 2021
0e2b8a9
Temp more backend tests
mitruska Aug 3, 2021
d91fd29
Add const to shape arg
mitruska Aug 3, 2021
ab454ba
Use span for slices calculation
mitruska Aug 5, 2021
5e6577b
Remove unused headers
mitruska Aug 5, 2021
a3cb838
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 5, 2021
956169f
CumSum new ref tests
mitruska Aug 10, 2021
2412fba
Add more ref tests
mitruska Aug 10, 2021
244d1a3
Add all cumsum modes ref tests
mitruska Aug 10, 2021
d6b68aa
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 10, 2021
d7be7a4
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 13, 2021
0f26fcb
new optimized cum_sum reference
mitruska Aug 13, 2021
41da650
Add reverse mode
mitruska Aug 13, 2021
c623175
Optimized cumsum ref
mitruska Aug 13, 2021
9c3aadc
Remove deprecated cumsum backend tests
mitruska Aug 13, 2021
37833f5
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 13, 2021
a17cd41
Add more CumSum reference tests
mitruska Aug 17, 2021
88e1afa
Simplify CumSum shared layer tests SetUp
mitruska Aug 17, 2021
ce68fca
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 17, 2021
06a9724
Replace auto to size_t in loop
mitruska Aug 19, 2021
d9fb153
Change static_cast to T{}
mitruska Aug 19, 2021
da14f56
Merge remote-tracking branch 'upstream/master' into mitruska/cum_sum_ref
mitruska Aug 19, 2021
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
193 changes: 193 additions & 0 deletions docs/template_plugin/tests/functional/op_reference/cum_sum.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <gtest/gtest.h>

#include <ie_core.hpp>
#include <ie_ngraph_utils.hpp>
#include <ngraph/ngraph.hpp>
#include <shared_test_classes/base/layer_test_utils.hpp>
#include <tuple>

#include "base_reference_test.hpp"

using namespace reference_tests;
using namespace ngraph;
using namespace InferenceEngine;

namespace {
struct CumSumParams {
// Custom axis input and attributes
template <class IT, class AT>
CumSumParams(const PartialShape& shape, const element::Type& iType, const std::vector<IT>& iValues, const std::vector<IT>& oValues, const bool execlusive,
const bool reverse, const element::Type& axisType, AT axisVal, const PartialShape& axisShape)
: execlusive(execlusive),
reverse(reverse),
axisValue(axisVal),
axisShape(axisShape),
inShape(shape),
axisType(axisType),
inType(iType),
outType(iType),
axisData(CreateBlob(axisType, std::vector<AT> {axisVal})),
inputData(CreateBlob(iType, iValues)),
refData(CreateBlob(iType, oValues)),
testDefaults(false) {}

// Default axis input and attributes
template <class IT>
CumSumParams(const PartialShape& shape, const element::Type& iType, const std::vector<IT>& iValues, const std::vector<IT>& oValues)
: inShape(shape),
axisType(element::i32),
inType(iType),
outType(iType),
inputData(CreateBlob(iType, iValues)),
refData(CreateBlob(iType, oValues)),
testDefaults(true) {}

bool execlusive = false;
bool reverse = false;
int64_t axisValue = 0;

PartialShape axisShape;
PartialShape inShape;
element::Type axisType;
element::Type inType;
element::Type outType;
Blob::Ptr axisData;
Blob::Ptr inputData;
Blob::Ptr refData;

bool testDefaults = false;
};

class ReferenceCumSumLayerTest : public testing::TestWithParam<CumSumParams>, public CommonReferenceTest {
public:
void SetUp() override {
auto params = GetParam();
if (params.testDefaults) {
function = CreateFunction(params.inShape, params.inType);
inputData = {params.inputData};
refOutData = {params.refData};
} else {
function = CreateFunction(params.inShape, params.inType, params.axisShape, params.axisType, params.execlusive, params.reverse);
inputData = {params.inputData, params.axisData};
refOutData = {params.refData};
}
}
static std::string getTestCaseName(const testing::TestParamInfo<CumSumParams>& obj) {
auto param = obj.param;
std::ostringstream result;
result << "testDefaults=" << param.testDefaults << "_";
result << "axisValue=" << param.axisValue << "_";
result << "execlusive=" << param.execlusive << "_";
result << "reverse=" << param.reverse << "_";
result << "inShape=" << param.inShape << "_";
result << "iType=" << param.inType << "_";
result << "axisType=" << param.axisType << "_";
result << "oType=" << param.outType;
return result.str();
}

private:
static std::shared_ptr<Function> CreateFunction(const PartialShape& data_shape, const element::Type& data_type, const PartialShape& axis_shape,
const element::Type& axis_type, const bool execlusive, const bool reverse) {
const auto data_param = std::make_shared<op::Parameter>(data_type, data_shape);
const auto axis_param = std::make_shared<op::Parameter>(axis_type, axis_shape);
const auto cum_sum = std::make_shared<op::v0::CumSum>(data_param, axis_param, execlusive, reverse);
return std::make_shared<Function>(NodeVector {cum_sum}, ParameterVector {data_param, axis_param});
}

static std::shared_ptr<Function> CreateFunction(const PartialShape& data_shape, const element::Type& data_type) {
const auto data_param = std::make_shared<op::Parameter>(data_type, data_shape);
const auto cum_sum = std::make_shared<op::v0::CumSum>(data_param);
return std::make_shared<Function>(NodeVector {cum_sum}, ParameterVector {data_param});
}
};

TEST_P(ReferenceCumSumLayerTest, CompareWithHardcodedRefs) {
Exec();
}

template <element::Type_t IN_ET>
std::vector<CumSumParams> generateCumSumParams(const element::Type& type) {
using T = typename element_type_traits<IN_ET>::value_type;
std::vector<CumSumParams> opParams {
// Default axis input and attributes
CumSumParams(PartialShape {1}, type, std::vector<T> {3}, std::vector<T> {3}),
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {1, 3, 6, 10, 15, 21}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {0, 1, 2, 3, 4, 6, 8, 10}),
// Custom axis input and attributes
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {1, 3, 6, 10, 15, 21}, false, false, element::i32, int32_t(0),
PartialShape {}), // axis i32
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {1, 3, 6, 10, 15, 21}, false, false, element::i64, int64_t(0),
PartialShape {}), // axis i64
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {21, 20, 18, 15, 11, 6}, false, true, element::i64, int64_t(0),
PartialShape {}),
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {0, 1, 3, 6, 10, 15}, true, false, element::i64, int64_t(0),
PartialShape {}),
CumSumParams(PartialShape {6}, type, std::vector<T> {1, 2, 3, 4, 5, 6}, std::vector<T> {20, 18, 15, 11, 6, 0}, true, true, element::i64, int64_t(0),
PartialShape {}),

CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {0, 1, 2, 3, 4, 6, 8, 10}, false, false, element::i32,
int32_t(0), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {4, 6, 8, 10, 4, 5, 6, 7}, false, true, element::i32,
int32_t(0), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {0, 0, 0, 0, 0, 1, 2, 3}, true, false, element::i32,
int32_t(0), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {4, 5, 6, 7, 0, 0, 0, 0}, true, true, element::i32,
int32_t(0), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {0, 1, 3, 6, 4, 9, 15, 22}, false, false, element::i32,
int32_t(1), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {0, 0, 1, 3, 0, 4, 9, 15}, true, false, element::i32,
int32_t(1), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {6, 6, 5, 3, 22, 18, 13, 7}, false, true, element::i32,
int32_t(1), PartialShape {}),
CumSumParams(PartialShape {2, 4}, type, std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7}, std::vector<T> {6, 5, 3, 0, 18, 13, 7, 0}, true, true, element::i32,
int32_t(1), PartialShape {}),

CumSumParams(PartialShape {3, 2, 4}, type,
std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23},
std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 14, 16, 18, 20, 22,
24, 27, 30, 33, 36, 39, 42, 45},
false, false, element::i32, int32_t(0), PartialShape {}),
CumSumParams(PartialShape {3, 2, 4}, type,
std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23},
std::vector<T> {0, 1, 2, 3, 4, 6, 8, 10,
8, 9, 10, 11, 20, 22, 24, 26,
16, 17, 18, 19, 36, 38, 40, 42},
false, false, element::i32, int32_t(1), PartialShape {}),
CumSumParams(PartialShape {3, 2, 4}, type,
std::vector<T> {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23},
std::vector<T> {0, 1, 3, 6, 4, 9, 15, 22,
8, 17, 27, 38, 12, 25, 39, 54,
16, 33, 51, 70, 20, 41, 63, 86},
false, false, element::i32, int32_t(2), PartialShape {}),
};
return opParams;
}

std::vector<CumSumParams> generateCumSumCombinedParams() {
const std::vector<std::vector<CumSumParams>> opTypeParams {
generateCumSumParams<element::Type_t::bf16>(element::bf16), generateCumSumParams<element::Type_t::f16>(element::f16),
generateCumSumParams<element::Type_t::f32>(element::f32), generateCumSumParams<element::Type_t::i32>(element::i32),
generateCumSumParams<element::Type_t::i64>(element::i64), generateCumSumParams<element::Type_t::u32>(element::u32),
generateCumSumParams<element::Type_t::i8>(element::i8)};
std::vector<CumSumParams> combinedParams;
std::for_each(opTypeParams.begin(), opTypeParams.end(), [&](std::vector<CumSumParams> params) {
combinedParams.insert(combinedParams.end(), params.begin(), params.end());
});
return combinedParams;
}

INSTANTIATE_TEST_SUITE_P(smoke_CumSum_With_Hardcoded_Refs, ReferenceCumSumLayerTest, ::testing::ValuesIn(generateCumSumCombinedParams()),
ReferenceCumSumLayerTest::getTestCaseName);
} // namespace
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,12 @@ void CumSumLayerTest::SetUp() {
bool exclusive, reverse;
int64_t axis;
std::tie(inputShapes, inputPrecision, axis, exclusive, reverse, targetDevice) = this->GetParam();
auto inType = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inputPrecision);
ngraph::ParameterVector paramVector;
auto paramData = std::make_shared<ngraph::opset1::Parameter>(inType, ngraph::Shape(inputShapes));
paramVector.push_back(paramData);
const auto inType = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inputPrecision);
const auto paramData = std::make_shared<ngraph::op::Parameter>(inType, ngraph::Shape(inputShapes));
const auto axisNode = std::make_shared<ngraph::op::Constant>(ngraph::element::Type_t::i64, ngraph::Shape{}, std::vector<int64_t>{axis})->output(0);
const auto cumSum = std::make_shared<ngraph::op::v0::CumSum>(paramData, axisNode, exclusive, reverse);

auto axisNode = std::make_shared<ngraph::op::Constant>(ngraph::element::Type_t::i64, ngraph::Shape{}, std::vector<int64_t>{axis})->output(0);

auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(paramVector));
auto cumSum = std::dynamic_pointer_cast<ngraph::op::CumSum>(ngraph::builder::makeCumSum(paramOuts[0], axisNode, exclusive, reverse));

ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(cumSum)};
function = std::make_shared<ngraph::Function>(results, paramVector, "cumsum");
ngraph::ResultVector results{std::make_shared<ngraph::op::Result>(cumSum)};
function = std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{paramData}, "cumsum");
}
} // namespace LayerTestsDefinitions
108 changes: 21 additions & 87 deletions ngraph/core/reference/include/ngraph/runtime/reference/cum_sum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,107 +5,41 @@
#pragma once

#include <cmath>
#include <map>
#include <utility>
#include <vector>

#include "ngraph/coordinate_transform.hpp"
#include "ngraph/type/bfloat16.hpp"
#include "ngraph/type/float16.hpp"

namespace ngraph {
namespace runtime {
namespace reference {

template <typename T, typename P>
void cumsum(const T* arg,
const P* axis_tensor,
T* out,
const Shape& tensor_shape,
const bool exclusive,
const bool reverse) {
NGRAPH_SUPPRESS_DEPRECATED_START
CoordinateTransform temp_transform(tensor_shape);
for (const Coordinate& output_coord : temp_transform) {
out[temp_transform.index(output_coord)] = 0;
}

P axis = axis_tensor[0];
P rank = tensor_shape.size();

if (axis < -rank || axis > rank) {
throw ngraph_error("axis must be in the range [-rank, rank]");
}
axis = axis < 0 ? rank + axis : axis;

auto get_key = [&, axis](const Coordinate& coord) -> Coordinate {
Coordinate result(coord.size(), 0);
result[axis] = coord[axis];

for (size_t i = 0; i < coord.size(); i++) {
result[i] = coord[i] - result[i];
}
return result;
};

auto update_output_buffer =
[&](size_t input_index, size_t output_index, T& prev, std::vector<std::pair<size_t, T>>& tensor_vec) -> void {
tensor_vec[input_index].second = prev + tensor_vec[input_index].second;
out[tensor_vec[output_index].first] = tensor_vec[input_index].second;

// update prev to hold the last result value to compute ruuning sum for
// subsequent iter
prev = out[tensor_vec[output_index].first];
};

auto cum_sum = [&, exclusive, reverse](std::vector<std::pair<size_t, T>>& tensor_vec) {
if (!reverse) {
T prev = 0;
for (size_t i = 0; i < tensor_vec.size(); i++) {
if (exclusive && i == 0) {
out[tensor_vec[i].first] = prev;
continue;
}
// we will compute running sum of j-1 elements if exlusive=1 or else
// for j elements if exclusive = 0
size_t arg_index = exclusive == 1 ? i - 1 : i;
update_output_buffer(arg_index, i, prev, tensor_vec);
const auto rank = tensor_shape.size();
const auto axis = axis_tensor[0] >= 0 ? axis_tensor[0] : rank + axis_tensor[0];
const auto axis_dim = tensor_shape[axis];

const auto size_before_axis = shape_size(Shape(tensor_shape.begin(), tensor_shape.begin() + axis));
const auto size_after_axis = shape_size(Shape(tensor_shape.begin() + axis + 1, tensor_shape.end()));

const auto reverse_shift = reverse ? -1 : 1;
const auto element_shift = exclusive ? size_after_axis * reverse_shift : 0;

for (size_t i = 0; i < size_before_axis; ++i) {
const auto slice_idx = i * axis_dim * size_after_axis + reverse * size_after_axis * (axis_dim - 1);
for (size_t j = 0; j < size_after_axis; ++j) {
const auto sequence_start_idx = slice_idx + j;
out[sequence_start_idx] = exclusive ? T{0} : arg[sequence_start_idx];
for (size_t k = 1; k < axis_dim; ++k) {
const auto element_idx = sequence_start_idx + (k * size_after_axis) * reverse_shift;
const auto in_idx = element_idx - element_shift;
const auto previous_sum_idx = element_idx - size_after_axis * reverse_shift;
out[element_idx] = out[previous_sum_idx] + arg[in_idx];
}
} else // reverse == true
{
T prev = 0;
for (size_t i = tensor_vec.size(); i-- > 0;) {
if (exclusive && i == tensor_vec.size() - 1) {
out[tensor_vec[i].first] = prev;
continue;
}
// we will compute running sum of j-1 elements if exlusive=1 or else
// for j elements if exclusive = 0
size_t arg_index = exclusive == 1 ? i + 1 : i;
update_output_buffer(arg_index, i, prev, tensor_vec);
}
}
};

// Map to collect tensor elements belonging to the same axis
std::map<Coordinate, std::vector<std::pair<size_t, T>>> map_cooord_to_val;
CoordinateTransform input_transform(tensor_shape);
for (const Coordinate& input_coord : input_transform) {
// points to the current element in the input tensor
T current = arg[input_transform.index(input_coord)];
auto key = get_key(input_coord);
auto index = input_transform.index(input_coord);
if (map_cooord_to_val.find(key) != map_cooord_to_val.end()) {
map_cooord_to_val[key].push_back(std::make_pair(index, current));
} else {
map_cooord_to_val.insert({key, std::vector<std::pair<size_t, T>>()});
map_cooord_to_val[key].push_back(std::make_pair(index, current));
}
}
// iterate the map and perform cumulative sum over the give axis
for (auto& it : map_cooord_to_val) {
cum_sum(it.second);
}
NGRAPH_SUPPRESS_DEPRECATED_END
}
} // namespace reference
} // namespace runtime
Expand Down
1 change: 0 additions & 1 deletion ngraph/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ set(MULTI_TEST_SRC
backend/cosh.in.cpp
backend/ctc_greedy_decoder.in.cpp
backend/ctc_greedy_decoder_seq_len.in.cpp
backend/cum_sum.in.cpp
backend/deformable_psroi_pooling.in.cpp
backend/detection_output.in.cpp
backend/dft.in.cpp
Expand Down
Loading