From c3db2db56fa032f0dd27e208079d2f5d40a63f3b Mon Sep 17 00:00:00 2001 From: eclipsess Date: Fri, 25 May 2018 17:59:11 +0800 Subject: [PATCH] add transpose and regist op --- src/framework/operator.h | 1 + src/operators/batchnorm_op.cpp | 4 ++ src/operators/box_coder_op.cpp | 4 ++ src/operators/concat_op.cpp | 4 ++ src/operators/elementwise_add_op.cpp | 4 ++ src/operators/kernel/arm/transpose_kernel.cpp | 72 +++++++++++++++++++ src/operators/kernel/transpose_kernel.h | 32 +++++++++ src/operators/lrn_op.cpp | 4 ++ src/operators/mul_op.cpp | 4 ++ src/operators/multiclass_nms_op.cpp | 4 ++ src/operators/op_param.h | 20 ++++++ src/operators/pool_op.cpp | 4 ++ src/operators/prior_box_op.cpp | 4 ++ src/operators/softmax_op.cpp | 4 ++ src/operators/transpose_op.cpp | 53 ++++++++++++++ src/operators/transpose_op.h | 52 ++++++++++++++ test/CMakeLists.txt | 4 ++ test/executor_for_test.h | 2 + test/operators/test_transpose_op.cpp | 50 +++++++++++++ 19 files changed, 326 insertions(+) create mode 100644 src/operators/kernel/arm/transpose_kernel.cpp create mode 100644 src/operators/kernel/transpose_kernel.h create mode 100644 src/operators/transpose_op.cpp create mode 100644 src/operators/transpose_op.h create mode 100644 test/operators/test_transpose_op.cpp diff --git a/src/framework/operator.h b/src/framework/operator.h index bd9db2802c..3de5aba72b 100644 --- a/src/framework/operator.h +++ b/src/framework/operator.h @@ -25,6 +25,7 @@ limitations under the License. */ #include "framework/attribute.h" #include "framework/op_info.h" #include "framework/op_kernel_type.h" +#include "framework/op_registry.h" #include "framework/paddle_mobile_object.h" #include "framework/program/block_desc.h" #include "framework/program/program-optimize/node.h" diff --git a/src/operators/batchnorm_op.cpp b/src/operators/batchnorm_op.cpp index d12fa35c55..44200db856 100644 --- a/src/operators/batchnorm_op.cpp +++ b/src/operators/batchnorm_op.cpp @@ -25,3 +25,7 @@ void BatchNormOp::InferShape() const { template class BatchNormOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(batchnorm); +REGISTER_OPERATOR(batchnorm, ops::BatchNormOp); diff --git a/src/operators/box_coder_op.cpp b/src/operators/box_coder_op.cpp index e6907c6859..ca653b5711 100644 --- a/src/operators/box_coder_op.cpp +++ b/src/operators/box_coder_op.cpp @@ -48,3 +48,7 @@ void BoxCoderOp::InferShape() const { template class BoxCoderOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(box_coder); +REGISTER_OPERATOR(box_coder, ops::BoxCoderOp); diff --git a/src/operators/concat_op.cpp b/src/operators/concat_op.cpp index 22d496b7c2..6744b47b77 100644 --- a/src/operators/concat_op.cpp +++ b/src/operators/concat_op.cpp @@ -58,3 +58,7 @@ template class ConcatOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(concat); +REGISTER_OPERATOR(concat, ops::ConcatOp); diff --git a/src/operators/elementwise_add_op.cpp b/src/operators/elementwise_add_op.cpp index 15ca204311..1eff80152b 100644 --- a/src/operators/elementwise_add_op.cpp +++ b/src/operators/elementwise_add_op.cpp @@ -25,3 +25,7 @@ void ElementwiseAddOp::InferShape() const { template class ElementwiseAddOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(elementwise_add); +REGISTER_OPERATOR(elementwise_add, ops::ElementwiseAddOp); diff --git a/src/operators/kernel/arm/transpose_kernel.cpp b/src/operators/kernel/arm/transpose_kernel.cpp new file mode 100644 index 0000000000..92b5916ec4 --- /dev/null +++ b/src/operators/kernel/arm/transpose_kernel.cpp @@ -0,0 +1,72 @@ +/* Copyright (c) 2018 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/transpose_kernel.h" + +namespace paddle_mobile { +namespace operators { + +template +void TransposeFunc(const int numel, const T* input, const vector axis, + const vector old_strides, const vector new_strides, + T* output) { + for (int i = 0; i < numel; ++i) { + int old_idx = 0; + int idx = i; + for (int j = 0; j < axis.size(); ++j) { + int order = axis[j]; + old_idx += (idx / new_strides[j]) * old_strides[order]; + idx %= new_strides[j]; + } + output[i] = input[old_idx]; + } +} + +template <> +void TransposeKernel::Compute(const TransposeParam& param) const { + const auto* input_x = param.InputX(); + const auto input_x_dims = input_x->dims(); + auto* out = param.Out(); + const auto axis = param.Axis(); + const auto* input_x_data = input_x->data(); + auto* out_data = out->mutable_data(); + + size_t axis_size = axis.size(); + std::vector new_dims; + new_dims.reserve(axis_size); + for (auto c : axis) { + new_dims.push_back(input_x_dims[c]); + } + + std::vector old_strides; + std::vector new_strides; + for (int i = 0; i < axis.size(); i++) { + int temp_old = 1; + int temp_new = 1; + for (int j = i + 1; j < axis.size(); j++) { + temp_old *= input_x_dims[j]; + temp_new *= new_dims[j]; + } + old_strides.push_back(temp_old); + new_strides.push_back(temp_new); + } + + TransposeFunc(input_x->numel(), input_x_data, axis, old_strides, + new_strides, out_data); +} + +} // namespace operators +} // namespace paddle_mobile diff --git a/src/operators/kernel/transpose_kernel.h b/src/operators/kernel/transpose_kernel.h new file mode 100644 index 0000000000..aa7d890209 --- /dev/null +++ b/src/operators/kernel/transpose_kernel.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2018 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. */ + +#include + +#include "framework/operator.h" +#include "operators/op_param.h" + +#pragma once; + +namespace paddle_mobile { +namespace operators { + +template +class TransposeKernel + : public framework::OpKernelBase { + public: + void Compute(const TransposeParam& param) const; +}; +} // namespace operators +} // namespace paddle_mobile diff --git a/src/operators/lrn_op.cpp b/src/operators/lrn_op.cpp index 6babb5fd20..cc89a034b4 100644 --- a/src/operators/lrn_op.cpp +++ b/src/operators/lrn_op.cpp @@ -25,3 +25,7 @@ void LrnOp::InferShape() const { template class LrnOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(lrn); +REGISTER_OPERATOR(lrn, ops::LrnOp); diff --git a/src/operators/mul_op.cpp b/src/operators/mul_op.cpp index 7097a7d543..80c20122f4 100644 --- a/src/operators/mul_op.cpp +++ b/src/operators/mul_op.cpp @@ -51,3 +51,7 @@ void MulOp::InferShape() const { template class MulOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(mul); +REGISTER_OPERATOR(mul, ops::MulOp); diff --git a/src/operators/multiclass_nms_op.cpp b/src/operators/multiclass_nms_op.cpp index 305e15151a..bc796010b2 100644 --- a/src/operators/multiclass_nms_op.cpp +++ b/src/operators/multiclass_nms_op.cpp @@ -35,3 +35,7 @@ void MultiClassNMSOp::InferShape() const { template class MultiClassNMSOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(multiclass_nms); +REGISTER_OPERATOR(multiclass_nms, ops::MultiClassNMSOp); diff --git a/src/operators/op_param.h b/src/operators/op_param.h index 64e121d89a..bdb745b2e1 100644 --- a/src/operators/op_param.h +++ b/src/operators/op_param.h @@ -583,5 +583,25 @@ class MultiClassNMSParam : public OpParam { float score_threshold_; }; +class TransposeParam : public OpParam { + public: + TransposeParam(const VariableNameMap &inputs, const VariableNameMap &outputs, + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); + axis_ = GetAttr>("axis", attrs); + } + + const Tensor *InputX() const { return input_x_; } + + Tensor *Out() const { return out_; } + + const vector &Axis() const { return axis_; } + + private: + Tensor *input_x_; + Tensor *out_; + vector axis_; +}; } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/pool_op.cpp b/src/operators/pool_op.cpp index 0bd861fd79..a8521e0e73 100644 --- a/src/operators/pool_op.cpp +++ b/src/operators/pool_op.cpp @@ -54,3 +54,7 @@ void PoolOp::InferShape() const { template class PoolOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(pool2d); +REGISTER_OPERATOR(pool2d, ops::PoolOp); diff --git a/src/operators/prior_box_op.cpp b/src/operators/prior_box_op.cpp index f5186af810..3928c3db53 100644 --- a/src/operators/prior_box_op.cpp +++ b/src/operators/prior_box_op.cpp @@ -45,3 +45,7 @@ void PriorBoxOp::InferShape() const { template class PriorBoxOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(prior_box); +REGISTER_OPERATOR(prior_box, ops::PriorBoxOp); diff --git a/src/operators/softmax_op.cpp b/src/operators/softmax_op.cpp index 87bfd1a494..c353d0b882 100644 --- a/src/operators/softmax_op.cpp +++ b/src/operators/softmax_op.cpp @@ -23,3 +23,7 @@ void SoftmaxOp::InferShape() const { template class SoftmaxOp; } // namespace operators } // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(softmax); +REGISTER_OPERATOR(softmax, ops::SoftmaxOp); diff --git a/src/operators/transpose_op.cpp b/src/operators/transpose_op.cpp new file mode 100644 index 0000000000..e21338bf1b --- /dev/null +++ b/src/operators/transpose_op.cpp @@ -0,0 +1,53 @@ +/* Copyright (c) 2018 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. */ + +#include "operators/transpose_op.h" +#include +#include +namespace paddle_mobile { +namespace operators { + +template +void TransposeOp::InferShape() const { + auto input_x_dims = param_.InputX()->dims(); + auto axis = param_.Axis(); + + size_t x_dims_size = input_x_dims.size(); + size_t axis_size = axis.size(); + + PADDLE_MOBILE_ENFORCE((x_dims_size == axis_size), + "input_dims must " + "be equal to the axis_size. ") + + std::vector count(axis_size, 0); + for (size_t i = 0; i < axis_size; i++) { + PADDLE_MOBILE_ENFORCE( + axis[i] < static_cast(axis_size) && ++count[axis[i]] == 1, + "Each element of Attribute axis should be a unique value " + "range from 0 to (dims - 1), " + "where the dims is the axis's size"); + } + framework::DDim out_dims(input_x_dims); + for (size_t i = 0; i < axis_size; i++) { + out_dims[i] = input_x_dims[axis[i]]; + } + param_.Out()->Resize(out_dims); +} +template class TransposeOp; +} // namespace operators +} // namespace paddle_mobile + +namespace ops = paddle_mobile::operators; +USE_OP(transpose); +REGISTER_OPERATOR(transpose, ops::TransposeOp); diff --git a/src/operators/transpose_op.h b/src/operators/transpose_op.h new file mode 100644 index 0000000000..a56771b4c6 --- /dev/null +++ b/src/operators/transpose_op.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2018 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 + +#include "framework/operator.h" +#include "operators/kernel/transpose_kernel.h" +#include "operators/op_param.h" + +namespace paddle_mobile { +namespace operators { + +using paddle_mobile::framework::Tensor; + +template +class TransposeOp : public framework::OperatorWithKernel { + public: + TransposeOp(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 Run() const { + operators::TransposeKernel kernel; + kernel.Compute(param_); + } + + using framework::OperatorWithKernel::OperatorWithKernel; + void InferShape() const override; + + protected: + TransposeParam param_; +}; + +} // namespace operators +} // namespace paddle_mobile diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 79c7f15a74..2a413f01cd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,6 +34,10 @@ target_link_libraries(test-priorbox-op paddle-mobile) ADD_EXECUTABLE(test-boxcoder-op operators/test_box_coder_op.cpp test_helper.h test_include.h) target_link_libraries(test-boxcoder-op paddle-mobile) +# gen test +ADD_EXECUTABLE(test-transpose-op operators/test_transpose_op.cpp test_helper.h test_include.h) +target_link_libraries(test-transpose-op paddle-mobile) + # gen test ADD_EXECUTABLE(test-multiclassnms-op operators/test_multiclass_nms_op.cpp test_helper.h test_include.h) target_link_libraries(test-multiclassnms-op paddle-mobile) diff --git a/test/executor_for_test.h b/test/executor_for_test.h index bf74a6ef3b..90193157f2 100644 --- a/test/executor_for_test.h +++ b/test/executor_for_test.h @@ -15,11 +15,13 @@ limitations under the License. */ #pragma once #include +#include #include "common/log.h" #include "framework/executor.h" #include "operators/conv_op.h" #include "operators/pool_op.h" #include "operators/softmax_op.h" +#include "operators/transpose_op.h" using paddle_mobile::framework::BlockDesc; using paddle_mobile::framework::DDim; diff --git a/test/operators/test_transpose_op.cpp b/test/operators/test_transpose_op.cpp new file mode 100644 index 0000000000..ffdb34f2f5 --- /dev/null +++ b/test/operators/test_transpose_op.cpp @@ -0,0 +1,50 @@ +/* Copyright (c) 2018 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. */ + +#include "../executor_for_test.h" +#include "../test_helper.h" +#include "./io.h" + +int main() { + paddle_mobile::Loader loader; + auto program = loader.Load(std::string("../../test/models/mobilenet+ssd")); + if (program.originProgram == nullptr) { + DLOG << "program read file"; + } + Executor4Test> + executor(program, "transpose"); + paddle_mobile::framework::Tensor input; + SetupTensor(&input, {1, 2, 3, 4}, static_cast(0), + static_cast(1)); + auto input_ptr = input.data(); + auto out_ddim = paddle_mobile::framework::make_ddim({1, 3, 4, 2}); + auto output = + executor.predict(input, "conv2d_22.tmp_1", "transpose_0.tmp_0", out_ddim); + auto *output_ptr = output->data(); + + DLOG << "input : "; + for (int j = 0; j < input.numel(); ++j) { + DLOG << " index " << j << " : " << input_ptr[j]; + } + + DLOG << "output : "; + for (int j = 0; j < output->numel(); ++j) { + DLOG << " index " << j << " : " << output_ptr[j]; + } + DLOG << " for example : "; + DLOG << " you can check if input[16] == output[9] "; + DLOG << " you can check if input[12] == output[1] "; + return 0; +} -- GitLab