diff --git a/include/tim/vx/ops/elementwise.h b/include/tim/vx/ops/elementwise.h index 905e0cb..23a758a 100644 --- a/include/tim/vx/ops/elementwise.h +++ b/include/tim/vx/ops/elementwise.h @@ -78,7 +78,6 @@ DECLARE_ELEMENTWISE_OP(Minimum) DECLARE_ELEMENTWISE_OP(Maximum) DECLARE_ELEMENTWISE_OP(Add) DECLARE_ELEMENTWISE_OP(Sub) -DECLARE_ELEMENTWISE_OP(Div) DECLARE_ELEMENTWISE_OP(Pow) DECLARE_ELEMENTWISE_OP(FloorDiv) @@ -89,6 +88,13 @@ class Multiply : public Operation { std::shared_ptr Clone(std::shared_ptr& graph) const override; }; +class Div : public Operation { + public: + Div(Graph* graph, float scale = 1.0f); + + std::shared_ptr Clone(std::shared_ptr& graph) const override; +}; + #undef DECLARE_ELEMENTWISE_OP } // namespace ops diff --git a/src/tim/vx/ops/elementwise.cc b/src/tim/vx/ops/elementwise.cc index 98abcad..1589949 100644 --- a/src/tim/vx/ops/elementwise.cc +++ b/src/tim/vx/ops/elementwise.cc @@ -41,7 +41,6 @@ DEFINE_ELEMENTWISE_OP(Minimum, VSI_NN_OP_MINIMUM) DEFINE_ELEMENTWISE_OP(Maximum, VSI_NN_OP_MAXIMUM) DEFINE_ELEMENTWISE_OP(Add, VSI_NN_OP_ADD) DEFINE_ELEMENTWISE_OP(Sub, VSI_NN_OP_SUBTRACT) -DEFINE_ELEMENTWISE_OP(Div, VSI_NN_OP_DIVIDE) DEFINE_ELEMENTWISE_OP(Pow, VSI_NN_OP_POW) DEFINE_ELEMENTWISE_OP(FloorDiv, VSI_NN_OP_FLOORDIV) @@ -58,6 +57,17 @@ std::shared_ptr Multiply::Clone( this->impl_->node_->nn_param.multiply.scale); } +Div::Div(Graph* graph, float scale) + : Operation(graph, VSI_NN_OP_DIVIDE, 2, 1) { + this->impl()->node()->nn_param.divide.scale = scale; +} + +std::shared_ptr Div::Clone( + std::shared_ptr& graph) const { + return graph->CreateOperation
( + this->impl_->node_->nn_param.divide.scale); +} + } // namespace ops } // namespace vx } // namespace tim diff --git a/src/tim/vx/ops/elementwise_test.cc b/src/tim/vx/ops/elementwise_test.cc index 41a904f..842d7e0 100644 --- a/src/tim/vx/ops/elementwise_test.cc +++ b/src/tim/vx/ops/elementwise_test.cc @@ -130,3 +130,108 @@ TEST(FloorDiv, shape_5_1_broadcast_uint8) { EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); EXPECT_EQ(golden, output); } + +TEST(Div, shape_1_fp32) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType io_shape({1}); + tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, + io_shape, tim::vx::TensorAttribute::INPUT); + tim::vx::TensorSpec output_spec(tim::vx::DataType::FLOAT32, + io_shape, tim::vx::TensorAttribute::OUTPUT); + + auto input_tensor_x = graph->CreateTensor(input_spec); + auto input_tensor_y = graph->CreateTensor(input_spec); + auto output_tensor = graph->CreateTensor(output_spec); + + std::vector in_data_x = { 1 }; + std::vector in_data_y = { 0 }; + std::vector golden = { std::numeric_limits::infinity() }; + + EXPECT_TRUE(input_tensor_x->CopyDataToTensor(in_data_x.data(), in_data_x.size()*4)); + EXPECT_TRUE(input_tensor_y->CopyDataToTensor(in_data_y.data(), in_data_y.size()*4)); + auto op = graph->CreateOperation(); + (*op).BindInputs({input_tensor_x, input_tensor_y}).BindOutputs({output_tensor}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + std::vector output(1); + + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} + +TEST(Div, shape_5_1_broadcast_uint8) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType in_shape_x({1}); + tim::vx::ShapeType in_shape_y({5, 1}); + tim::vx::ShapeType out_shape({5, 1}); + tim::vx::Quantization quant(tim::vx::QuantType::ASYMMETRIC, 1, 0); + tim::vx::Quantization quant_out(tim::vx::QuantType::ASYMMETRIC, 0.5, 0); + tim::vx::TensorSpec input_spec_x(tim::vx::DataType::UINT8, + in_shape_x, tim::vx::TensorAttribute::INPUT, quant); + tim::vx::TensorSpec input_spec_y(tim::vx::DataType::UINT8, + in_shape_y, tim::vx::TensorAttribute::INPUT, quant); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, + out_shape, tim::vx::TensorAttribute::OUTPUT, quant_out); + + auto input_tensor_x = graph->CreateTensor(input_spec_x); + auto input_tensor_y = graph->CreateTensor(input_spec_y); + auto output_tensor = graph->CreateTensor(output_spec); + + std::vector in_data_x = { 255 }; + std::vector in_data_y = { 1, 2, 3, 0, 255 }; + std::vector golden = { 255, 255, 170, 255, 2 }; + + EXPECT_TRUE(input_tensor_x->CopyDataToTensor(in_data_x.data(), in_data_x.size())); + EXPECT_TRUE(input_tensor_y->CopyDataToTensor(in_data_y.data(), in_data_y.size())); + auto op = graph->CreateOperation(); + (*op).BindInputs({input_tensor_x, input_tensor_y}).BindOutputs({output_tensor}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + std::vector output(5); + + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} + +TEST(Div, shape_5_1_broadcast_scale_uint8) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType in_shape_x({1}); + tim::vx::ShapeType in_shape_y({5, 1}); + tim::vx::ShapeType out_shape({5, 1}); + tim::vx::Quantization quant(tim::vx::QuantType::ASYMMETRIC, 1, 0); + tim::vx::Quantization quant_out(tim::vx::QuantType::ASYMMETRIC, 0.5, 0); + tim::vx::TensorSpec input_spec_x(tim::vx::DataType::UINT8, + in_shape_x, tim::vx::TensorAttribute::INPUT, quant); + tim::vx::TensorSpec input_spec_y(tim::vx::DataType::UINT8, + in_shape_y, tim::vx::TensorAttribute::INPUT, quant); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, + out_shape, tim::vx::TensorAttribute::OUTPUT, quant_out); + + auto input_tensor_x = graph->CreateTensor(input_spec_x); + auto input_tensor_y = graph->CreateTensor(input_spec_y); + auto output_tensor = graph->CreateTensor(output_spec); + + std::vector in_data_x = { 128 }; + std::vector in_data_y = { 1, 2, 3, 0, 255 }; + std::vector golden = { 128, 64, 43, 255, 1 }; + + EXPECT_TRUE(input_tensor_x->CopyDataToTensor(in_data_x.data(), in_data_x.size())); + EXPECT_TRUE(input_tensor_y->CopyDataToTensor(in_data_y.data(), in_data_y.size())); + auto op = graph->CreateOperation(0.5f); + (*op).BindInputs({input_tensor_x, input_tensor_y}).BindOutputs({output_tensor}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + std::vector output(5); + + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +}