From 123c037ee86ce40685fc405c9a84e81db980fbdc Mon Sep 17 00:00:00 2001 From: eclipsess Date: Thu, 17 May 2018 11:54:23 +0800 Subject: [PATCH] add elementwise_add_op --- CMakeLists.txt | 3 +- src/operators/elementwise_add_op.cpp | 31 +++ src/operators/elementwise_add_op.h | 51 +++++ .../kernel/arm/elementwise_add_kernel.cpp | 41 ++++ src/operators/kernel/elementwise_add_kernel.h | 36 ++++ src/operators/math/elementwise_op_function.h | 204 ++++++++++++++++++ src/operators/math/transform.h | 53 +++++ src/operators/op_param.h | 114 ++++++++++ test/elementwise_add_op_test.h | 157 ++++++++++++++ test/main.cpp | 5 +- test/test_helper.h | 8 +- test/test_include.h | 15 ++ 12 files changed, 711 insertions(+), 7 deletions(-) create mode 100644 src/operators/elementwise_add_op.cpp create mode 100644 src/operators/elementwise_add_op.h create mode 100644 src/operators/kernel/arm/elementwise_add_kernel.cpp create mode 100644 src/operators/kernel/elementwise_add_kernel.h create mode 100644 src/operators/math/elementwise_op_function.h create mode 100644 src/operators/math/transform.h create mode 100644 test/elementwise_add_op_test.h create mode 100644 test/test_include.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 18cf94f303..d999a35467 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,5 +46,6 @@ target_link_libraries(paddle-mobile-static protobuf-lite openblas) add_dependencies(paddle-mobile openblas_proj) # gen test -ADD_EXECUTABLE(paddle-mobile-test test/main.cpp test/test_helper.h) +ADD_EXECUTABLE(paddle-mobile-test test/main.cpp test/test_helper.h + test/elementwise_add_op_test.h test/test_include.h) target_link_libraries(paddle-mobile-test paddle-mobile) diff --git a/src/operators/elementwise_add_op.cpp b/src/operators/elementwise_add_op.cpp new file mode 100644 index 0000000000..b26776a7ca --- /dev/null +++ b/src/operators/elementwise_add_op.cpp @@ -0,0 +1,31 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +==============================================================================*/ + +#include "elementwise_add_op.h" + +namespace paddle_mobile { +namespace operators { + +template +void ElementwiseAddOp::InferShape() const { + auto x_dim = param_.InputX()->dims(); + param_.Out()->Resize(x_dim); +} +template class ElementwiseAddOp; +} +} diff --git a/src/operators/elementwise_add_op.h b/src/operators/elementwise_add_op.h new file mode 100644 index 0000000000..b75dc44994 --- /dev/null +++ b/src/operators/elementwise_add_op.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +==============================================================================*/ + +#include "framework/operator.h" +#include "kernel/elementwise_add_kernel.h" +#include "op_param.h" + +namespace paddle_mobile { +namespace operators { + +using namespace framework; + +template +class ElementwiseAddOp : public framework::OperatorWithKernel { +public: + ElementwiseAddOp(const std::string &type, const VariableNameMap &inputs, + const VariableNameMap &outputs, + const framework::AttributeMap attrs, + std::shared_ptr scope) + : framework::OperatorWithKernel(type, inputs, outputs, attrs, + scope), + param_(inputs, outputs, attrs, *scope) {} + + void RunImpl() const { + operators::ElementwiseAddKernel kernel; + kernel.Compute(param_); + } + + using framework::OperatorWithKernel::OperatorWithKernel; + void InferShape() const override; + +protected: + ElementwiseAddParam param_; +}; +} +} \ No newline at end of file diff --git a/src/operators/kernel/arm/elementwise_add_kernel.cpp b/src/operators/kernel/arm/elementwise_add_kernel.cpp new file mode 100644 index 0000000000..6796d874ff --- /dev/null +++ b/src/operators/kernel/arm/elementwise_add_kernel.cpp @@ -0,0 +1,41 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once + +#include "operators/kernel/elementwise_add_kernel.h" + +namespace paddle_mobile { +namespace operators { + +template struct AddFunctor { + inline T operator()(T a, T b) const { return a + b; } +}; + +template <> +void ElementwiseAddKernel::Compute( + const ElementwiseAddParam ¶m) const { + const Tensor *input_x = param.InputX(); + const Tensor *input_y = param.InputY(); + Tensor *Out = param.Out(); + Out->mutable_data(); + const int axis = param.Axis(); + ElementwiseComputeEx, float>(input_x, input_y, axis, + AddFunctor(), Out); +} + +template class ElementwiseAddKernel; + +} // namespace operators +} // namespace paddle diff --git a/src/operators/kernel/elementwise_add_kernel.h b/src/operators/kernel/elementwise_add_kernel.h new file mode 100644 index 0000000000..5554b7b064 --- /dev/null +++ b/src/operators/kernel/elementwise_add_kernel.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +==============================================================================*/ +#pragma once; + +#include "framework/operator.h" +#include "operators/math/elementwise_op_function.h" +#include "operators/op_param.h" + +namespace paddle_mobile { +namespace operators { + +using namespace framework; + +template +class ElementwiseAddKernel + : public framework::OpKernelBase { +public: + void Compute(const ElementwiseAddParam ¶m) const; +}; +} +} diff --git a/src/operators/math/elementwise_op_function.h b/src/operators/math/elementwise_op_function.h new file mode 100644 index 0000000000..5b1f93c861 --- /dev/null +++ b/src/operators/math/elementwise_op_function.h @@ -0,0 +1,204 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once +#include "transform.h" + +#define UNLIKELY(condition) __builtin_expect(static_cast(condition), 0) + +namespace paddle_mobile { +namespace operators { + +/* + * Out = X ⊙ Y + * If Y's shape does not match X' shape, they will be reshaped. + * For example: + * 1. shape(X) = (2, 3, 4, 5), shape(Y) = (3, 4), with axis=1 + * pre=2, n=3*4, post=5 + * x.shape(2, 12, 5) * y.shape(1, 12, 1).broadcast(2, 12, 5) + * 2. shape(X) = (2, 3, 4, 5), shape(Y) = (4,5) + * pre=2*3, n=4*5, post=1 + * x.shape(6, 20, 1) * y.shape(1, 20, 1).broadcast(6, 20, 1) + */ +inline void get_mid_dims(const framework::DDim &x_dims, + const framework::DDim &y_dims, const int axis, + int *pre, int *n, int *post) { + *pre = 1; + *n = 1; + *post = 1; + // compute pre + for (int i = 0; i < axis; ++i) { + (*pre) *= x_dims[i]; + } + + for (int i = 0; i < y_dims.size(); ++i) { + assert(x_dims[i + axis] == y_dims[i]); + /// "Broadcast dimension mismatch."); + (*n) *= y_dims[i]; + } + + for (int i = axis + y_dims.size(); i < x_dims.size(); ++i) { + (*post) *= x_dims[i]; + } +} + +/// remove dims tail 1. (4,20,1,1) -> (4,20) +inline void trim_trailing_singular_dims(framework::DDim *dims) { + // Remove trailing dimensions of size 1 for y + auto actual_dims_size = dims->size(); + for (; actual_dims_size != 0; --actual_dims_size) { + if ((*dims)[actual_dims_size - 1] != 1) + break; + } + if (actual_dims_size != dims->size()) { + auto actual_dims = framework::vectorize(*dims); + actual_dims.resize(actual_dims_size); + *dims = framework::make_ddim(actual_dims); + } +} + +template class RowwiseTransformIterator { +public: + RowwiseTransformIterator(const T *ptr, int n) : ptr_(ptr), i_(0), n_(n) {} + + RowwiseTransformIterator &operator++() { + ++i_; + if (UNLIKELY(i_ == n_)) { + i_ = 0; + } + return *this; + } + + bool operator==(const RowwiseTransformIterator &rhs) const { + return (ptr_ + i_) == &(*rhs); + } + + bool operator!=(const RowwiseTransformIterator &rhs) const { + return (ptr_ + i_) != &(*rhs); + } + + const T &operator*() { return ptr_[i_]; } + +private: + const T *ptr_; + int i_; + int64_t n_; +}; + +/// (4,20,2)+(20,): (20,) just as (20,1), when move 2 strides in last dimension +/// in (4,20,2) is 2 , +/// (20,1) move 1 stride , to fill(add) 2 element with the same number. +template class MidWiseTransformIterator { +public: + MidWiseTransformIterator(const T *ptr, int n, int post) + : ptr_(ptr), i_(0), j_(0), n_(n), post_(post) {} + + MidWiseTransformIterator &operator++() { + ++j_; + if (UNLIKELY(j_ == post_)) { + ++i_; + j_ = 0; + if (UNLIKELY(i_ == n_)) { + i_ = 0; + } + } + return *this; + } + + bool operator==(const MidWiseTransformIterator &rhs) const { + return (ptr_ + i_) == &(*rhs); + } + + bool operator!=(const MidWiseTransformIterator &rhs) const { + return (ptr_ + i_) != &(*rhs); + } + + const T &operator*() { return ptr_[i_]; } + +private: + const T *ptr_; + int64_t i_; + int64_t j_; + int64_t n_; + int64_t post_; +}; + +template +class TransformFunctor { +public: + TransformFunctor(const framework::Tensor *x, const framework::Tensor *y, + framework::Tensor *z, Functor func) + : x_(x->data()), y_(y->data()), z_(z->mutable_data()), + nx_(x->numel()), func_(func) {} + + inline void Run() const { + math::Transform trans; + // 同时执行func(x_, y_)传入z_。 + trans(x_, x_ + nx_, y_, z_, func_); + } + + inline void RunRowWise(int n, int pre) const { + math::Transform trans; + trans(x_, x_ + nx_, RowwiseTransformIterator(y_, n), z_, func_); + } + + inline void RunMidWise(int n, int pre, int post) const { + math::Transform trans; + trans(x_, x_ + nx_, MidWiseTransformIterator(y_, n, post), z_, func_); + } + +private: + const T *x_; + const T *y_; + OutType *z_; + int64_t nx_; + Functor func_; +}; + +template +void ElementwiseComputeEx(const framework::Tensor *x, + const framework::Tensor *y, int axis, Functor func, + framework::Tensor *z) { + TransformFunctor functor(x, y, z, func); + + auto x_dims = x->dims(); + auto y_dims = y->dims(); + // PADDLE_ENFORCE_GE(x_dims.size(), y_dims.size(), + // "Rank of first input must >= rank of second input."); + + if (x_dims == y_dims) { + functor.Run(); + return; + } + + /// axis = -1 represent the last dimension. + axis = (axis == -1 ? x_dims.size() - y_dims.size() : axis); + // PADDLE_ENFORCE(axis >= 0 && axis < x_dims.size(), + // "Axis should be in range [0, x_dims)"); + trim_trailing_singular_dims(&y_dims); + axis = (y_dims.size() == 0) ? x_dims.size() : axis; + + int pre, n, post; + get_mid_dims(x_dims, y_dims, axis, &pre, &n, &post); + if (post == 1) { + functor.RunRowWise(n, pre); + return; + } else { + functor.RunMidWise(n, pre, post); + return; + } +} + +} // namespace operators +} // namespace paddle diff --git a/src/operators/math/transform.h b/src/operators/math/transform.h new file mode 100644 index 0000000000..1fdaf4c548 --- /dev/null +++ b/src/operators/math/transform.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once + +#include + +namespace paddle_mobile { +namespace operators { +namespace math { + +// Transform applys a unary or a binary functor on each element in a +// range defined by a pair of iterators. +// +// - The specialization for CPU calls std::transform. +// - The specialization for CUDA calls thrust::tranform. +// +// NOTE: We need to define InputIter and OutputIter defined as +// different types, because the InputIter points op's inputs and +// OutputIter pints to op's outputs. +// +// NOTE: We don't assume that InputIter to be const InputType* and +// OutputIter to be OutputType*, because we might use a iterator +// class, paddle::fluid::operators::RowwiseTRansformIterator. + +struct Transform { + template + void operator()(InputIter first, InputIter last, OutputIter result, + UnaryOperation op) { + std::transform(first, last, result, op); + } + + template + void operator()(InputIter1 first1, InputIter1 last1, InputIter2 first2, + OutputIter result, BinaryOperation op) { + std::transform(first1, last1, first2, result, op); + } +}; +} +} // namespace platform +} // namespace paddle diff --git a/src/operators/op_param.h b/src/operators/op_param.h index 01463008a8..9ecf56f2b1 100644 --- a/src/operators/op_param.h +++ b/src/operators/op_param.h @@ -37,11 +37,32 @@ protected: return GetVarValue("Input", inputs, scope); } + template + static T *InputXFrom(const VariableNameMap &inputs, const Scope &scope) { + return GetVarValue("X", inputs, scope); + } + + template + static T *InputYFrom(const VariableNameMap &inputs, const Scope &scope) { + return GetVarValue("Y", inputs, scope); + } + + template + static std::vector InputMultiFrom(const VariableNameMap &inputs, + const Scope &scope) { + return GetMultiVarValue("Input", inputs, scope); + } + template static T *OutputFrom(const VariableNameMap &outputs, const Scope &scope) { return GetVarValue("Output", outputs, scope); } + template + static T *OutFrom(const VariableNameMap &outputs, const Scope &scope) { + return GetVarValue("Out", outputs, scope); + } + template static T *FilterFrom(const VariableNameMap &inputs, const Scope &scope) { return GetVarValue("Filter", inputs, scope); @@ -64,6 +85,20 @@ protected: return nullptr; } } + + template + static std::vector GetMultiVarValue(std::string key, + const VariableNameMap &var_map, + const Scope &scope) { + auto var_vecs = var_map.at(key); + assert(var_vecs.size() > 1); + std::vector var_res; + for (auto &var_vec : var_vecs) { + auto var = scope.FindVar(var_vec); + var_res.push_back(var->GetMutable()); + } + return var_res; + } }; class ConvParam : OpParam { @@ -106,5 +141,84 @@ private: std::ostream &operator<<(std::ostream &os, const ConvParam &conv_param); +class ElementwiseAddParam : OpParam { +public: + ElementwiseAddParam(const VariableNameMap &inputs, + const VariableNameMap &outputs, + const framework::AttributeMap &attrs, + const framework::Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + input_y_ = InputYFrom(inputs, scope); + out_ = OutFrom(outputs, scope); + axis_ = GetAttr("axis", attrs); + } + + const Tensor *InputX() const { return input_x_; } + + const Tensor *InputY() const { return input_y_; } + + Tensor *Out() const { return out_; } + + const int &Axis() const { return axis_; } + +private: + Tensor *input_x_; + Tensor *input_y_; + Tensor *out_; + int axis_; +}; + +class MulParam : OpParam { +public: + MulParam(const VariableNameMap &inputs, const VariableNameMap &outputs, + const framework::AttributeMap &attrs, + const framework::Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + input_y_ = InputYFrom(inputs, scope); + out_ = OutFrom(outputs, scope); + x_num_col_dims_ = GetAttr("x_num_col_dims", attrs); + y_num_col_dims_ = GetAttr("y_num_col_dims", attrs); + } + + const Tensor *InputX() const { return input_x_; } + + const Tensor *InputY() const { return input_y_; } + + Tensor *Out() const { return out_; } + + const int &XNumColDims() const { return x_num_col_dims_; } + + const int &YNumColDims() const { return y_num_col_dims_; } + +private: + Tensor *input_x_; + Tensor *input_y_; + Tensor *out_; + int x_num_col_dims_; + int y_num_col_dims_; +}; + +class ConcatParam : public OpParam { +public: + ConcatParam(const VariableNameMap &inputs, const VariableNameMap &outputs, + const framework::AttributeMap &attrs, + const framework::Scope &scope) { + inputs_ = InputMultiFrom(inputs, scope); + out_ = OutFrom(outputs, scope); + axis_ = GetAttr("axis", attrs); + } + + std::vector Inputs() const { return inputs_; } + + Tensor *Out() const { return out_; } + + const int &Axis() const { return axis_; } + +private: + std::vector inputs_; + Tensor *out_; + int axis_; +}; + } // namespace operators } // namespace paddle_mobile diff --git a/test/elementwise_add_op_test.h b/test/elementwise_add_op_test.h new file mode 100644 index 0000000000..38287d2cbe --- /dev/null +++ b/test/elementwise_add_op_test.h @@ -0,0 +1,157 @@ + +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +==============================================================================*/ +#pragma once +#include "operators/elementwise_add_op.h" +#include "test_include.h" + +namespace paddle_mobile { +namespace framework { + +template class TestElementwiseAddOp { +public: + TestElementwiseAddOp(const Program p) : program_(p) { + if (use_optimize_) { + to_predict_program_ = program_.optimizeProgram; + } else { + to_predict_program_ = program_.originProgram; + } + + const std::vector> blocks = + to_predict_program_->Blocks(); + // std::cout << " **block size " << blocks.size() << std::endl; + for (int i = 0; i < blocks.size(); ++i) { + std::shared_ptr block_desc = blocks[i]; + std::vector> ops = block_desc->Ops(); + // std::cout << " ops " << ops.size() << std::endl; + for (int j = 0; j < ops.size(); ++j) { + std::shared_ptr op = ops[j]; + if (op->Type() == "elementwise_add") { + if (op->GetAttrMap().at("axis").Get() != -1) { + std::cout << "attr: axis = " + << op->GetAttrMap().at("axis").Get() << std::endl; + } + } + std::cout << "op:" << op->Type() << std::endl; + if (op->Type() == "elementwise_add" && + op->Input("X")[0] == "batch_norm_2.tmp_2") { + std::cout << " elementwise_add attr size: " << op->GetAttrMap().size() + << std::endl; + std::cout << " inputs size: " << op->GetInputs().size() << std::endl; + std::cout << " outputs size: " << op->GetOutputs().size() + << std::endl; + std::cout << " Input X is : " << op->Input("X")[0] << std::endl; + std::cout << " Input Y is : " << op->Input("Y")[0] << std::endl; + std::cout << " Output Out is : " << op->Output("Out")[0] << std::endl; + Attribute axis_attr = op->GetAttrMap().at("axis"); + int axis = axis_attr.Get(); + std::cout << " Attr axis is : " << axis << std::endl; + + std::shared_ptr> add = + std::make_shared>( + op->Type(), op->GetInputs(), op->GetOutputs(), + op->GetAttrMap(), program_.scope); + ops_of_block_[*block_desc.get()].push_back(add); + } + } + } + } + + std::shared_ptr predict_add(Tensor &t1, Tensor &t2) { + // feed + auto scope = program_.scope; + Variable *x_feed_value = scope->Var("batch_norm_2.tmp_2"); + auto tensor_x = x_feed_value->GetMutable(); + tensor_x->ShareDataWith(t1); + + Variable *y_feed_value = scope->Var("batch_norm_0.tmp_3"); + auto tensor_y = y_feed_value->GetMutable(); + tensor_y->ShareDataWith(t2); + + Variable *con_output = scope->Var("elementwise_add_0.tmp_0"); + Tensor *output_tensor = con_output->GetMutable(); + output_tensor->mutable_data({1, 3, 224, 224}); + // std::cout << typeid(output_tensor).name() << std::endl; + // std::cout << "output_tensor dims: " << output_tensor->dims() << + // std::endl; + + std::shared_ptr out_tensor = std::make_shared(); + out_tensor.reset(output_tensor); + + predict_add(t1, t2, 0); + return out_tensor; + } + +private: + const framework::Program program_; + std::shared_ptr to_predict_program_; + std::map>>> + ops_of_block_; + bool use_optimize_ = false; + + void predict_add(const Tensor &t1, const Tensor &t2, int block_id) { + std::shared_ptr to_predict_block = + to_predict_program_->Block(block_id); + for (int j = 0; j < ops_of_block_[*to_predict_block.get()].size(); ++j) { + auto op = ops_of_block_[*to_predict_block.get()][j]; + std::cout << "op -> run()" << std::endl; + op->Run(); + } + } +}; + +template class TestElementwiseAddOp; +} // namespace framework + +namespace test { +void testElementwiseAdd() { + paddle_mobile::Loader loader; + auto program = loader.Load(std::string( + "../../test/models/image_classification_resnet.inference.model")); + + /// input x (1,3,224,224) + paddle_mobile::framework::Tensor inputx; + SetupTensor(&inputx, {1, 3, 224, 224}, static_cast(0), + static_cast(1)); + float *inputx_ptr = inputx.data(); + /// input y (224,) + paddle_mobile::framework::Tensor inputy; + SetupTensor(&inputy, {224}, static_cast(0), + static_cast(1)); + float *inputy_ptr = inputy.data(); + + paddle_mobile::framework::TestElementwiseAddOp + testElementwiseAddOp(program); + + auto output_add = testElementwiseAddOp.predict_add(inputx, inputy); + float *output_add_ptr = output_add->data(); + for (int j = 0; j < output_add->numel(); ++j) { + // std::cout << "value of output: " << output_add_ptr[j] << std::endl; + } + + /// output (1,3,224,224) + std::cout << "output memory size : " << output_add->memory_size() + << std::endl; + std::cout << "output numel : " << output_add->numel() << std::endl; + + std::cout << inputx_ptr[226] << " + " << inputy_ptr[2] << " = " + << output_add_ptr[226] << std::endl; +} +} // namespace test +} // namespace paddle_mobile diff --git a/test/main.cpp b/test/main.cpp index 41ac36b39c..ca61c7ef9d 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -16,6 +16,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==============================================================================*/ +#include "elementwise_add_op_test.h" #include "framework/executor.h" #include "io.h" #include "test_helper.h" @@ -73,7 +74,7 @@ int main() { // float* output_ptr = output->data(); // for (int j = 0; j < output->numel(); ++j) { // std::cout << " value of output: " << output_ptr[j] << std::endl; - // } - + // + paddle_mobile::test::testElementwiseAdd(); return 0; } diff --git a/test/test_helper.h b/test/test_helper.h index 321fe53fa1..6306786f99 100644 --- a/test/test_helper.h +++ b/test/test_helper.h @@ -15,19 +15,19 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==============================================================================*/ - -#include +#pragma once #include "framework/ddim.h" #include "framework/tensor.h" +#include template -void SetupTensor(paddle_mobile::framework::Tensor* input, +void SetupTensor(paddle_mobile::framework::Tensor *input, paddle_mobile::framework::DDim dims, T lower, T upper) { static unsigned int seed = 100; std::mt19937 rng(seed++); std::uniform_real_distribution uniform_dist(0, 1); - T* input_ptr = input->mutable_data(dims); + T *input_ptr = input->mutable_data(dims); for (int i = 0; i < input->numel(); ++i) { input_ptr[i] = static_cast(uniform_dist(rng) * (upper - lower) + lower); } diff --git a/test/test_include.h b/test/test_include.h new file mode 100644 index 0000000000..476c2df938 --- /dev/null +++ b/test/test_include.h @@ -0,0 +1,15 @@ +#include "framework/block_desc.h" +#include "framework/framework.pb.h" +#include "framework/lod_tensor.h" +#include "framework/operator.h" +#include "framework/program.h" +#include "framework/program_desc.h" +#include "framework/scope.h" +#include "framework/tensor.h" +#include "framework/variable.h" +#include "framework/variable.h" +#include "io.h" +#include "test_helper.h" +#include +#include +#include \ No newline at end of file -- GitLab