Skip to content

Commit

Permalink
[onert/cpu] Support INT64 BinaryArithemtic operation (#13711)
Browse files Browse the repository at this point in the history
This commit updates cpu backend and cker to support INT64 BinaryArithmetic operations.

ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh <[email protected]>
  • Loading branch information
hseok-oh authored Aug 22, 2024
1 parent 0307ecf commit d4b3ebb
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 9 deletions.
2 changes: 2 additions & 0 deletions compute/cker/include/cker/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ struct BinaryArithmeticOpParam
// float activation params.
float float_activation_min = 0;
float float_activation_max = 0;
int64_t int64_activation_min = 0;
int64_t int64_activation_max = 0;

// Processed output dimensions.
// Let input "a" be the one that broadcasts in the faster-changing dimension.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ inline void BinaryArithmeticOp(const BinaryArithmeticOpParam &, const Shape &inp
}
}

template <>
inline void BinaryArithmeticOp(const BinaryArithmeticOpParam &params, const Shape &input1_shape,
const int64_t *input1_data, const Shape &input2_shape,
const int64_t *input2_data, const Shape &output_shape,
int64_t *output_data,
const std::function<int64_t(const int64_t &, const int64_t &)> &fn)
{
const int flat_size = MatchingElementsSize(input1_shape, input2_shape, output_shape);
for (int i = 0; i < flat_size; ++i)
{
output_data[i] = ActivationFunctionWithMinMax(
fn(input1_data[i], input2_data[i]), params.int64_activation_min, params.int64_activation_max);
}
}

template <typename T>
inline typename std::enable_if_t<is_quant8<T>::value> BroadcastBinaryArithmeticOpSlow(
const BinaryArithmeticOpParam &params, const Shape &input1_shape, const T *input1_data,
Expand Down Expand Up @@ -216,6 +231,35 @@ inline void BroadcastBinaryArithmeticOpSlow(
}
}

template <>
inline void BroadcastBinaryArithmeticOpSlow(
const BinaryArithmeticOpParam &params, const Shape &input1_shape, const int64_t *input1_data,
const Shape &input2_shape, const int64_t *input2_data, const Shape &output_shape,
int64_t *output_data, const std::function<int64_t(const int64_t &, const int64_t &)> &fn)
{
NdArrayDesc<4> desc1;
NdArrayDesc<4> desc2;
NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, &desc2);
const Shape extended_output_shape = Shape::ExtendedShape(4, output_shape);

for (int b = 0; b < extended_output_shape.Dims(0); ++b)
{
for (int y = 0; y < extended_output_shape.Dims(1); ++y)
{
for (int x = 0; x < extended_output_shape.Dims(2); ++x)
{
for (int c = 0; c < extended_output_shape.Dims(3); ++c)
{
output_data[Offset(extended_output_shape, b, y, x, c)] =
ActivationFunctionWithMinMax(fn(input1_data[SubscriptToIndex(desc1, b, y, x, c)],
input2_data[SubscriptToIndex(desc2, b, y, x, c)]),
params.int64_activation_min, params.int64_activation_max);
}
}
}
}
}

} // namespace reference
} // namespace cker
} // namespace nnfw
Expand Down
64 changes: 64 additions & 0 deletions compute/cker/src/Mul.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,70 @@ TEST(CKer_Operation, Mul)
EXPECT_EQ(output[i], expected_output[i]);
}

// Int64
{
// Shape: {1, 2, 2, 1}
std::vector<int64_t> input1 = {10, 9, -11, 3};
// Shape: {1, 2, 2, 1}
std::vector<int64_t> input2 = {2, -2, -3, 4};
std::vector<int64_t> expected_output = {20, -18, 33, 12};
std::vector<int64_t> output(4);

nnfw::cker::BinaryArithmeticOpParam param;
param.int64_activation_min = std::numeric_limits<int64_t>::lowest();
param.int64_activation_max = std::numeric_limits<int64_t>::max();
nnfw::cker::Shape shape{1, 2, 2, 1};

nnfw::cker::BinaryArithmeticOp<nnfw::cker::BinaryArithmeticOpType::MUL>(
param, shape, input1.data(), shape, input2.data(), shape, output.data());

for (size_t i = 0; i < expected_output.size(); ++i)
EXPECT_EQ(output[i], expected_output[i]);
}

// Int64 Relu
{
// Shape: {1, 2, 2, 1}
std::vector<int64_t> input1 = {10, 9, -11, 3};
// Shape: {1, 2, 2, 1}
std::vector<int64_t> input2 = {2, -2, -3, 4};
std::vector<int64_t> expected_output = {20, 0, 33, 12};
std::vector<int64_t> output(4);

nnfw::cker::BinaryArithmeticOpParam param;
param.int64_activation_min = 0;
param.int64_activation_max = std::numeric_limits<int64_t>::max();
nnfw::cker::Shape shape{1, 2, 2, 1};

nnfw::cker::BinaryArithmeticOp<nnfw::cker::BinaryArithmeticOpType::MUL>(
param, shape, input1.data(), shape, input2.data(), shape, output.data());

for (size_t i = 0; i < expected_output.size(); ++i)
EXPECT_EQ(output[i], expected_output[i]);
}

// Int64 Broadcast
{
// Shape: {1, 2, 2, 1}
std::vector<int64_t> input1 = {10, 9, -11, 3};
// Shape: {1}
std::vector<int64_t> input2 = {-3};
std::vector<int64_t> expected_output = {-30, -27, 33, -9};
std::vector<int64_t> output(4);

nnfw::cker::BinaryArithmeticOpParam param;
param.broadcast_category = nnfw::cker::BroadcastableOpCategory::kGenericBroadcast;
param.int64_activation_min = std::numeric_limits<int64_t>::lowest();
param.int64_activation_max = std::numeric_limits<int64_t>::max();

nnfw::cker::BroadcastBinaryArithmeticOp<nnfw::cker::BinaryArithmeticOpType::MUL>(
param, nnfw::cker::Shape{1, 2, 2, 1}, input1.data(), nnfw::cker::Shape{1}, input2.data(),
nnfw::cker::Shape{1, 2, 2, 1}, output.data());

for (size_t i = 0; i < expected_output.size(); ++i)
EXPECT_EQ(output[i], expected_output[i]);
}

// TODO Add other types
}

Expand Down
25 changes: 16 additions & 9 deletions runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ generateKernelGeneric(const IPortableTensor *lhs, const IPortableTensor *rhs,
return Eval<arithmetic_type, int32_t>(lhs, rhs, output, op_params);
break;
}
case OperandType::INT64:
{
int64_t output_activation_min = 0, output_activation_max = 0;
CalculateActivationRange(activation, &output_activation_min, &output_activation_max);
op_params.int64_activation_max = output_activation_max;
op_params.int64_activation_min = output_activation_min;
return Eval<arithmetic_type, int64_t>(lhs, rhs, output, op_params);
break;
}
case OperandType::BOOL8:
{
if (activation != ir::Activation::NONE)
Expand Down Expand Up @@ -253,19 +262,17 @@ void BinaryArithmeticLayer::configure(const IPortableTensor *lhs, const IPortabl
}
break;
case ArithmeticType::kDiv:
if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
if (_lhs->data_type() == OperandType::FLOAT32)
{
throw std::runtime_error{
"BinaryArithmetic(Div): Div operation does not support quantization"};
}
else if (_lhs->data_type() == OperandType::INT32)
{
throw std::runtime_error{"BinaryArithmetic(Div): Unsupported data type"};
_kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::DIV>(
_lhs, _rhs, _output, activation, op_params);
}
else
{
_kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::DIV>(
_lhs, _rhs, _output, activation, op_params);
// TODO Support quantized type
// TODO Support integer type with zero check
throw std::runtime_error{
"BinaryArithmetic(Div): Div operation does not support non-float data types yet"};
}
break;
default:
Expand Down

0 comments on commit d4b3ebb

Please sign in to comment.