From ddfa00ac7df6509a7e88336b9804304d0772e1b4 Mon Sep 17 00:00:00 2001 From: wangliu Date: Mon, 2 Jul 2018 23:19:43 +0800 Subject: [PATCH] move arm op kernels to central_arm_func --- doc/design_doc.md | 3 +- .../UserInterfaceState.xcuserstate | Bin 47258 -> 42209 bytes src/framework/scope.h | 12 +- src/jni/paddle_mobile_jni.cpp | 6 +- src/jni/paddle_mobile_jni.h | 4 +- src/operators/kernel/arm/conv_add_kernel.cpp | 105 +------------ src/operators/kernel/arm/pool_kernel.cpp | 69 +-------- src/operators/kernel/arm/sigmoid_kernel.cpp | 53 +------ src/operators/kernel/arm/softmax_kernel.cpp | 9 +- .../central-arm-func/conv_add_arm_func.h | 138 ++++++++++++++++++ .../kernel/central-arm-func/conv_arm_func.h | 18 +-- .../kernel/central-arm-func/pool_arm_func.h | 92 ++++++++++++ .../central-arm-func/sigmoid_arm_func.h | 82 +++++++++++ .../central-arm-func/softmax_arm_func.h | 30 ++++ src/operators/kernel/pool_kernel.h | 1 - src/operators/kernel/softmax_kernel.h | 2 - src/operators/math/depthwise_conv_3x3.cpp | 5 +- src/operators/math/pool_3x3.cpp | 7 +- src/operators/op_param.h | 118 +++++++-------- test/net/test_googlenet.cpp | 30 ++-- tools/build.sh | 4 +- 21 files changed, 457 insertions(+), 331 deletions(-) create mode 100644 src/operators/kernel/central-arm-func/conv_add_arm_func.h create mode 100644 src/operators/kernel/central-arm-func/pool_arm_func.h create mode 100644 src/operators/kernel/central-arm-func/sigmoid_arm_func.h create mode 100644 src/operators/kernel/central-arm-func/softmax_arm_func.h diff --git a/doc/design_doc.md b/doc/design_doc.md index 3407c78443..bf5f78e8d8 100644 --- a/doc/design_doc.md +++ b/doc/design_doc.md @@ -3,7 +3,6 @@ #### 以下是 paddle-mobile 代码的执行流程图: - ![执行流程图](http://otkwwi4x8.bkt.clouddn.com/2018-07-02-15305189473720.png) @@ -15,7 +14,6 @@ 先来看一下模型, 模型分为两种结构: 一种为参数文件是散开的, 如下图, 红框为模型结构的 protobuf 文件, 其余为参数文件 - ![模型描述](http://otkwwi4x8.bkt.clouddn.com/2018-07-02-15305190629577.png) @@ -23,6 +21,7 @@ ![模型描述combined](http://otkwwi4x8.bkt.clouddn.com/2018-07-02-15305191057130.png) + loader 模块的作用是将模型结构信息 load 进内存, 将红框内的 protobuf 文件 load 进内存, 并对模型结构进行优化(如将几个细粒度的 op 融合成 粗粒度的 op, 如将 conv、 add、 batchnorm、 relu 融合为 conv\_add\_batchnorm\_relu). 方便进行算法优化. diff --git a/ios/PaddleMobile.xcworkspace/xcuserdata/liuruilong.xcuserdatad/UserInterfaceState.xcuserstate b/ios/PaddleMobile.xcworkspace/xcuserdata/liuruilong.xcuserdatad/UserInterfaceState.xcuserstate index ff9a9abc7211d4c390fca9535743ee452515390e..a74810d22b023830a6e44d19984ff92302eb84a3 100644 GIT binary patch delta 20024 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 diff --git a/src/framework/scope.h b/src/framework/scope.h index d714f61af3..054f141ff6 100644 --- a/src/framework/scope.h +++ b/src/framework/scope.h @@ -23,7 +23,17 @@ namespace framework { class Scope { public: Scope() = default; - ~Scope() = default; + + ~Scope() { + for (auto &var : vars_) { + delete var.second; + } + vars_.clear(); + for (auto kid : kids_) { + delete kid; + } + kids_.clear(); + } Scope &NewScope() const; diff --git a/src/jni/paddle_mobile_jni.cpp b/src/jni/paddle_mobile_jni.cpp index 323d1e37c1..01d4e52a4b 100644 --- a/src/jni/paddle_mobile_jni.cpp +++ b/src/jni/paddle_mobile_jni.cpp @@ -54,13 +54,14 @@ string jstring2cppstring(JNIEnv *env, jstring jstr) { JNIEXPORT jboolean JNICALL Java_com_baidu_paddle_PML_load(JNIEnv *env, jclass thiz, jstring modelPath) { + ANDROIDLOGI("load invoked"); bool optimize = true; return getPaddleMobileInstance()->Load(jstring2cppstring(env, modelPath), optimize); } -JNIEXPORT jfloatArray JNICALL Java_com_baidu_paddle_PML_predictImage( - JNIEnv *env, jclass thiz, jfloatArray buf) { +JNIEXPORT jfloatArray JNICALL +Java_com_baidu_paddle_PML_predict(JNIEnv *env, jclass thiz, jfloatArray buf) { jfloatArray result = NULL; int count = 0; float *dataPointer = nullptr; @@ -78,6 +79,7 @@ JNIEXPORT jfloatArray JNICALL Java_com_baidu_paddle_PML_predictImage( count = output->numel(); result = env->NewFloatArray(count); env->SetFloatArrayRegion(result, 0, count, output->data()); + ANDROIDLOGI("predict finished"); return result; } diff --git a/src/jni/paddle_mobile_jni.h b/src/jni/paddle_mobile_jni.h index 3497144999..86caa9a273 100644 --- a/src/jni/paddle_mobile_jni.h +++ b/src/jni/paddle_mobile_jni.h @@ -31,8 +31,8 @@ JNIEXPORT jboolean JNICALL Java_com_baidu_paddle_PML_load(JNIEnv *env, /** * object detection for anroid */ -JNIEXPORT jfloatArray JNICALL Java_com_baidu_paddle_PML_predictImage( - JNIEnv *env, jclass thiz, jfloatArray buf); +JNIEXPORT jfloatArray JNICALL +Java_com_baidu_paddle_PML_predict(JNIEnv *env, jclass thiz, jfloatArray buf); /** * clear data of the net when destroy for android diff --git a/src/operators/kernel/arm/conv_add_kernel.cpp b/src/operators/kernel/arm/conv_add_kernel.cpp index 64d6dfa64d..88f839f611 100644 --- a/src/operators/kernel/arm/conv_add_kernel.cpp +++ b/src/operators/kernel/arm/conv_add_kernel.cpp @@ -14,6 +14,7 @@ limitations under the License. */ #ifdef FUSION_CONVADD_OP #include "operators/kernel/conv_add_kernel.h" +#include "../central-arm-func/conv_add_arm_func.h" namespace paddle_mobile { namespace operators { @@ -23,111 +24,9 @@ bool ConvAddKernel::Init(FusionConvAddParam *param) { return true; } -void ConvAddBasic(const FusionConvAddParam ¶m) { - const Tensor *input = param.Input(); - Tensor filter = *param.Filter(); - Tensor bias = *param.Bias(); - int axis = param.Axis(); - Tensor *output = param.Output(); - math::expand_bias(bias, axis, output->dims()); - output->ShareDataWith(bias); - int groups = param.Groups(); - std::vector strides = param.Strides(); - std::vector paddings = param.Paddings(); - std::vector dilations = param.Dilations(); - - const int batch_size = static_cast(input->dims()[0]); - - std::vector filter_shape_vec(framework::vectorize(filter.dims())); - - std::vector output_shape_vec(framework::vectorize(output->dims())); - size_t data_dim = filter_shape_vec.size() - 2; - std::vector col_shape_vec(1 + 2 * data_dim); - col_shape_vec[0] = input->dims()[1] / groups; - for (size_t j = 0; j < data_dim; ++j) { - col_shape_vec[j + 1] = filter_shape_vec[j + 2]; - col_shape_vec[j + 1 + data_dim] = output_shape_vec[j + 2]; - } - framework::DDim col_shape(framework::make_ddim(col_shape_vec)); - - framework::DDim col_matrix_shape = - framework::flatten_to_2d(col_shape, data_dim + 1); - - bool is_expand = - math::IsExpand(filter_shape_vec, strides, paddings, dilations); - Tensor col; - Tensor col_matrix; - if (is_expand) { - col.mutable_data(col_shape); - col_matrix.ShareDataWith(col); - col_matrix.Resize(col_matrix_shape); - } - - framework::DDim input_shape = framework::slice_ddim( - input->dims(), 1, static_cast(input->dims().size())); - - framework::DDim filter_matrix_shape = {filter.dims()[0], - filter.numel() / filter.dims()[0]}; - filter.Resize(filter_matrix_shape); - framework::DDim output_matrix_shape = { - output->dims()[1], - output->numel() / (output->dims()[0] * output->dims()[1])}; - - // convolution operator: im2col(or vol2col) + gemm - int in_step = static_cast(input->dims()[1]) / groups; - int out_step = static_cast(output->dims()[1]) / groups; - - math::Vol2ColFunctor vol2col; - math::Im2ColFunctor im2col; - - for (int i = 0; i < batch_size; i++) { - Tensor in_batch = input->Slice(i, i + 1).Resize(input_shape); - Tensor out_batch = output->Slice(i, i + 1).Resize(output_matrix_shape); - - for (int g = 0; g < groups; g++) { - Tensor in_slice = in_batch.Slice(g * in_step, (g + 1) * in_step); - - if (!is_expand) { - col.ShareDataWith(in_slice); - col_matrix.ShareDataWith(col); - col_matrix.Resize(col_matrix_shape); - } else if (data_dim == 2U) { - // im2col - im2col(in_slice, dilations, strides, - std::vector{paddings[0], paddings[1], paddings[0], - paddings[1]}, - &col); - } else if (data_dim == 3U) { - // vol2col - vol2col(in_slice, dilations, strides, paddings, &col); - } - // gemm - Tensor out_slice = out_batch.Slice(g * out_step, (g + 1) * out_step); - Tensor filter_slice = filter.Slice(g * out_step, (g + 1) * out_step); - math::matmul(filter_slice, false, col_matrix, false, - static_cast(1), &out_slice, - static_cast(1)); - } - } -} - template <> void ConvAddKernel::Compute(const FusionConvAddParam ¶m) const { - if (param.Groups() == param.Input()->dims()[1] && - param.Input()->dims()[1] == param.Output()->dims()[1] && - param.Filter()->dims()[2] == param.Filter()->dims()[3] && - param.Filter()->dims()[2] == 3 && param.Strides()[0] == 1) { - math::DepthwiseConv3x3s1p1(param.Input(), param.Filter(), param.Output(), - param.Bias(), true); - } else if (param.Groups() == param.Input()->dims()[1] && - param.Input()->dims()[1] == param.Output()->dims()[1] && - param.Filter()->dims()[2] == param.Filter()->dims()[3] && - param.Filter()->dims()[2] == 3) { - math::DepthwiseConv3x3(param.Input(), param.Strides(), param.Paddings(), - param.Filter(), param.Bias(), param.Output(), true); - } else { - ConvAddBasic(param); - } + ConvAddCompute(param); } template class ConvAddKernel; diff --git a/src/operators/kernel/arm/pool_kernel.cpp b/src/operators/kernel/arm/pool_kernel.cpp index 38e6c5f3f0..be2189340f 100644 --- a/src/operators/kernel/arm/pool_kernel.cpp +++ b/src/operators/kernel/arm/pool_kernel.cpp @@ -14,27 +14,11 @@ limitations under the License. */ #ifdef POOL_OP -#include -#include "common/log.h" - +#include "operators/kernel/pool_kernel.h" +#include "../central-arm-func/pool_arm_func.h" namespace paddle_mobile { namespace operators { -inline void PoolBasic(std::string pooling_type, std::vector ksize, - std::vector strides, std::vector paddings, - const Tensor *in_x, Tensor *out) { - if (pooling_type == "max") { - math::PoolFunctor, float> pool2d_forward; - math::MaxPool pool_process; - pool2d_forward(*in_x, ksize, strides, paddings, pool_process, out); - - } else if (pooling_type == "avg") { - math::PoolFunctor, float> pool2d_forward; - math::AvgPool pool_process; - pool2d_forward(*in_x, ksize, strides, paddings, pool_process, out); - } -} - template <> bool PoolKernel::Init(PoolParam *param) { return true; @@ -42,54 +26,7 @@ bool PoolKernel::Init(PoolParam *param) { template <> void PoolKernel::Compute(const PoolParam ¶m) const { - const Tensor *in_x = param.Input(); - Tensor *out = param.Output(); - std::string pooling_type = param.PoolingType(); - - std::vector ksize = param.Ksize(); - - std::vector strides = param.Strides(); - - std::vector paddings = param.Paddings(); - if (ksize.size() != 2) { - LOG(paddle_mobile::LogLevel::kLOG_ERROR) - << "Pool op only supports 2D and 3D input."; - } - - if (param.isGlobalPooling()) { - for (size_t i = 0; i < ksize.size(); ++i) { - paddings[i] = 0; - ksize[i] = static_cast(in_x->dims()[i + 2]); - } - } else if (ksize[0] == 3 && ksize[0] == ksize[1]) { - if (pooling_type == "max") { - if (strides[0] == strides[1] && strides[0] == 1 && - paddings[0] == paddings[1] && paddings[1] == 1) { - math::Pool3x3Maxs1p1(in_x, out); - } else { - math::Pool3x3Max(strides, paddings, in_x, out); - } - math::Pool3x3Max(strides, paddings, in_x, out); - } else if (pooling_type == "avg") { - if (strides[0] == strides[1] && strides[0] == 1 && - paddings[0] == paddings[1] && paddings[1] == 1) { - math::Pool3x3Avgs1p1(in_x, out); - } else { - math::Pool3x3Avg(strides, paddings, in_x, out); - } - math::Pool3x3Avg(strides, paddings, in_x, out); - } - - } else if (ksize[0] == 2 && ksize[0] == ksize[1]) { - if (pooling_type == "max") { - math::Pool2x2Max(strides, paddings, in_x, out); - } else if (pooling_type == "avg") { - math::Pool2x2Avg(strides, paddings, in_x, out); - } - - } else { - PoolBasic(pooling_type, ksize, strides, paddings, in_x, out); - } + PoolCompute(param); } } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/kernel/arm/sigmoid_kernel.cpp b/src/operators/kernel/arm/sigmoid_kernel.cpp index 5eb65cd6ce..eb67de153d 100644 --- a/src/operators/kernel/arm/sigmoid_kernel.cpp +++ b/src/operators/kernel/arm/sigmoid_kernel.cpp @@ -15,6 +15,7 @@ limitations under the License. */ #ifdef SIGMOID_OP #include "../sigmoid_kernel.h" +#include "../central-arm-func/sigmoid_arm_func.h" #if __ARM_NEON #include "../../math/math_func_neon.h" #endif @@ -25,52 +26,6 @@ namespace operators { using framework::DDim; using framework::Tensor; -void sigmoid(const Tensor *X, Tensor *Y) { -#if __ARM_NEON - const float *input = X->data(); - float *output = Y->mutable_data(); - const DDim &dDim = X->dims(); - int axis_index = 1; - if (dDim.size() < 4) { - axis_index = 0; - } - DDim outer_ddim = - paddle_mobile::framework::slice_ddim(dDim, 0, axis_index + 1); - DDim inner_ddim = - paddle_mobile::framework::slice_ddim(dDim, axis_index + 1, dDim.size()); - int out_size = paddle_mobile::framework::product(outer_ddim); - int inner_size = paddle_mobile::framework::product(inner_ddim); - - DLOG << "outsize=" << out_size; - DLOG << "innersize=" << inner_size; - #pragma omp parallel for - for (int i = 0; i < out_size; ++i) { - const float *input_outer_ptr = input + i * inner_size; - float *output_outer_ptr = output + i * inner_size; - int nn = inner_size >> 2; - int remain = inner_size - (nn << 2); - float32x4_t _one = vdupq_n_f32(1.f); - for (; nn > 0; nn--) { - float32x4_t data = vld1q_f32(input_outer_ptr); - data = vnegq_f32(data); - data = exp_ps(data); - data = vaddq_f32(data, _one); - float32x4_t out_data = vrecpeq_f32(data); - out_data = vmulq_f32(vrecpsq_f32(data, out_data), out_data); - vst1q_f32(output_outer_ptr, out_data); - - input_outer_ptr += 4; - output_outer_ptr += 4; - } - for (; remain > 0; remain--) { - *output_outer_ptr = 1.f / (1.f + exp(-*input_outer_ptr)); - output_outer_ptr++; - input_outer_ptr++; - } - } -#endif -} - template <> bool SigmoidKernel::Init(SigmoidParam *param) { return true; @@ -78,11 +33,7 @@ bool SigmoidKernel::Init(SigmoidParam *param) { template <> void SigmoidKernel::Compute(const SigmoidParam ¶m) const { - const Tensor *in_x = param.InputX(); - Tensor *out = param.Out(); - auto x_dims = in_x->dims(); - out->Resize(x_dims); - sigmoid(in_x, out); + SigmoidCompute(param); } template class SigmoidKernel; diff --git a/src/operators/kernel/arm/softmax_kernel.cpp b/src/operators/kernel/arm/softmax_kernel.cpp index 29006d48dc..3ce763be38 100644 --- a/src/operators/kernel/arm/softmax_kernel.cpp +++ b/src/operators/kernel/arm/softmax_kernel.cpp @@ -15,7 +15,8 @@ limitations under the License. */ #ifdef SOFTMAX_OP #include "../softmax_kernel.h" -#include "../../math/softmax.h" +#include "../central-arm-func/softmax_arm_func.h" +#include "operators/math/softmax.h" namespace paddle_mobile { namespace operators { @@ -26,11 +27,7 @@ bool SoftmaxKernel::Init(SoftmaxParam *param) { template <> void SoftmaxKernel::Compute(const SoftmaxParam ¶m) const { - const Tensor *in_x = param.InputX(); - Tensor *out = param.Out(); - auto x_dims = in_x->dims(); - out->Resize(x_dims); - math::SoftmaxFuntor()(in_x, out); + SoftmaxCompute(param); } template class SoftmaxKernel; diff --git a/src/operators/kernel/central-arm-func/conv_add_arm_func.h b/src/operators/kernel/central-arm-func/conv_add_arm_func.h new file mode 100644 index 0000000000..ed6dc46a90 --- /dev/null +++ b/src/operators/kernel/central-arm-func/conv_add_arm_func.h @@ -0,0 +1,138 @@ +/* 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. */ + +#ifdef FUSION_CONVADD_OP +#pragma once + +#include +#include "operators/math/conv_func.h" +#include "operators/math/depthwise_conv_3x3.h" +#include "operators/math/im2col.h" +#include "operators/math/math_function.h" +#include "operators/math/vol2col.h" +#include "operators/op_param.h" + +namespace paddle_mobile { +namespace operators { +void ConvAddBasic(const FusionConvAddParam ¶m) { + const Tensor *input = param.Input(); + Tensor filter = *param.Filter(); + Tensor bias = *param.Bias(); + int axis = param.Axis(); + Tensor *output = param.Output(); + math::expand_bias(bias, axis, output->dims()); + output->ShareDataWith(bias); + int groups = param.Groups(); + std::vector strides = param.Strides(); + std::vector paddings = param.Paddings(); + std::vector dilations = param.Dilations(); + + const int batch_size = static_cast(input->dims()[0]); + + std::vector filter_shape_vec(framework::vectorize(filter.dims())); + + std::vector output_shape_vec(framework::vectorize(output->dims())); + size_t data_dim = filter_shape_vec.size() - 2; + std::vector col_shape_vec(1 + 2 * data_dim); + col_shape_vec[0] = input->dims()[1] / groups; + for (size_t j = 0; j < data_dim; ++j) { + col_shape_vec[j + 1] = filter_shape_vec[j + 2]; + col_shape_vec[j + 1 + data_dim] = output_shape_vec[j + 2]; + } + framework::DDim col_shape(framework::make_ddim(col_shape_vec)); + + framework::DDim col_matrix_shape = + framework::flatten_to_2d(col_shape, data_dim + 1); + + bool is_expand = + math::IsExpand(filter_shape_vec, strides, paddings, dilations); + Tensor col; + Tensor col_matrix; + if (is_expand) { + col.mutable_data(col_shape); + col_matrix.ShareDataWith(col); + col_matrix.Resize(col_matrix_shape); + } + + framework::DDim input_shape = framework::slice_ddim( + input->dims(), 1, static_cast(input->dims().size())); + + framework::DDim filter_matrix_shape = {filter.dims()[0], + filter.numel() / filter.dims()[0]}; + filter.Resize(filter_matrix_shape); + framework::DDim output_matrix_shape = { + output->dims()[1], + output->numel() / (output->dims()[0] * output->dims()[1])}; + + // convolution operator: im2col(or vol2col) + gemm + int in_step = static_cast(input->dims()[1]) / groups; + int out_step = static_cast(output->dims()[1]) / groups; + + math::Vol2ColFunctor vol2col; + math::Im2ColFunctor im2col; + + for (int i = 0; i < batch_size; i++) { + Tensor in_batch = input->Slice(i, i + 1).Resize(input_shape); + Tensor out_batch = output->Slice(i, i + 1).Resize(output_matrix_shape); + + for (int g = 0; g < groups; g++) { + Tensor in_slice = in_batch.Slice(g * in_step, (g + 1) * in_step); + + if (!is_expand) { + col.ShareDataWith(in_slice); + col_matrix.ShareDataWith(col); + col_matrix.Resize(col_matrix_shape); + } else if (data_dim == 2U) { + // im2col + im2col(in_slice, dilations, strides, + std::vector{paddings[0], paddings[1], paddings[0], + paddings[1]}, + &col); + } else if (data_dim == 3U) { + // vol2col + vol2col(in_slice, dilations, strides, paddings, &col); + } + // gemm + Tensor out_slice = out_batch.Slice(g * out_step, (g + 1) * out_step); + Tensor filter_slice = filter.Slice(g * out_step, (g + 1) * out_step); + math::matmul(filter_slice, false, col_matrix, false, + static_cast(1), &out_slice, + static_cast(1)); + } + } +} + +template +void ConvAddCompute(const FusionConvAddParam ¶m) { + if (param.Groups() == param.Input()->dims()[1] && + param.Input()->dims()[1] == param.Output()->dims()[1] && + param.Filter()->dims()[2] == param.Filter()->dims()[3] && + param.Filter()->dims()[2] == 3 && param.Strides()[0] == 1) { + math::DepthwiseConv3x3s1p1(param.Input(), param.Filter(), param.Output(), + param.Bias(), true); + } else if (param.Groups() == param.Input()->dims()[1] && + param.Input()->dims()[1] == param.Output()->dims()[1] && + param.Filter()->dims()[2] == param.Filter()->dims()[3] && + param.Filter()->dims()[2] == 3) { + math::DepthwiseConv3x3(param.Input(), param.Strides(), param.Paddings(), + param.Filter(), param.Bias(), param.Output(), true); + } else { + ConvAddBasic(param); + } +} + +} // namespace operators +} // namespace paddle_mobile + +#endif diff --git a/src/operators/kernel/central-arm-func/conv_arm_func.h b/src/operators/kernel/central-arm-func/conv_arm_func.h index 6accf1937d..33caded3af 100644 --- a/src/operators/kernel/central-arm-func/conv_arm_func.h +++ b/src/operators/kernel/central-arm-func/conv_arm_func.h @@ -15,19 +15,21 @@ limitations under the License. */ #ifdef CONV_OP #pragma once -#include #include - +#include "operators/math/conv_func.h" +#include "operators/math/depthwise_conv_3x3.h" +#include "operators/math/im2col.h" +#include "operators/math/math_function.h" +#include "operators/math/vol2col.h" #include "operators/op_param.h" namespace paddle_mobile { namespace operators { - inline void ConvBasic(const ConvParam ¶m) { const Tensor *input = param.Input(); Tensor filter = *param.Filter(); Tensor *output = param.Output(); - + output->mutable_data(); int groups = param.Groups(); std::vector strides = param.Strides(); std::vector paddings = param.Paddings(); @@ -111,20 +113,18 @@ inline void ConvBasic(const ConvParam ¶m) { template void ConvCompute(const ConvParam ¶m) { - Tensor Bias; - Bias.mutable_data({param.Groups()}); if (param.Groups() == param.Input()->dims()[1] && param.Input()->dims()[1] == param.Output()->dims()[1] && param.Filter()->dims()[2] == param.Filter()->dims()[3] && param.Filter()->dims()[2] == 3 && param.Strides()[0] == 1) { math::DepthwiseConv3x3s1p1(param.Input(), param.Filter(), param.Output(), - &Bias, false); + nullptr, false); } else if (param.Groups() == param.Input()->dims()[1] && param.Input()->dims()[1] == param.Output()->dims()[1] && param.Filter()->dims()[2] == param.Filter()->dims()[3] && - param.Filter()->dims()[2] == 3 && param.Strides()[0] == 2) { + param.Filter()->dims()[2] == 3) { math::DepthwiseConv3x3(param.Input(), param.Strides(), param.Paddings(), - param.Filter(), &Bias, param.Output(), false); + param.Filter(), nullptr, param.Output(), false); } else { ConvBasic(param); } diff --git a/src/operators/kernel/central-arm-func/pool_arm_func.h b/src/operators/kernel/central-arm-func/pool_arm_func.h new file mode 100644 index 0000000000..9eb8aceb1a --- /dev/null +++ b/src/operators/kernel/central-arm-func/pool_arm_func.h @@ -0,0 +1,92 @@ +/* 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. */ + +#ifdef POOL_OP +#pragma once + +#include +#include +#include "operators/math/pooling.h" + +namespace paddle_mobile { +namespace operators { +using framework::Tensor; + +inline void PoolBasic(std::string pooling_type, std::vector ksize, + std::vector strides, std::vector paddings, + const Tensor *in_x, Tensor *out) { + if (pooling_type == "max") { + math::PoolFunctor, float> pool2d_forward; + math::MaxPool pool_process; + pool2d_forward(*in_x, ksize, strides, paddings, pool_process, out); + + } else if (pooling_type == "avg") { + math::PoolFunctor, float> pool2d_forward; + math::AvgPool pool_process; + pool2d_forward(*in_x, ksize, strides, paddings, pool_process, out); + } +} +template +void PoolCompute(const PoolParam ¶m) { + const Tensor *in_x = param.Input(); + Tensor *out = param.Output(); + std::string pooling_type = param.PoolingType(); + + std::vector ksize = param.Ksize(); + + std::vector strides = param.Strides(); + + std::vector paddings = param.Paddings(); + if (ksize.size() != 2) { + LOG(paddle_mobile::LogLevel::kLOG_ERROR) + << "Pool op only supports 2D and 3D input."; + } + + if (param.isGlobalPooling()) { + for (size_t i = 0; i < ksize.size(); ++i) { + paddings[i] = 0; + ksize[i] = static_cast(in_x->dims()[i + 2]); + } + } else if (ksize[0] == 3 && ksize[0] == ksize[1]) { + if (pooling_type == "max") { + if (strides[0] == strides[1] && strides[0] == 1 && + paddings[0] == paddings[1] && paddings[1] == 1) { + math::Pool3x3Maxs1p1(in_x, out); + } else { + math::Pool3x3Max(strides, paddings, in_x, out); + } + } else if (pooling_type == "avg") { + if (strides[0] == strides[1] && strides[0] == 1 && + paddings[0] == paddings[1] && paddings[1] == 1) { + math::Pool3x3Avgs1p1(in_x, out); + } else { + math::Pool3x3Avg(strides, paddings, in_x, out); + } + } + + } else if (ksize[0] == 2 && ksize[0] == ksize[1]) { + if (pooling_type == "max") { + math::Pool2x2Max(strides, paddings, in_x, out); + } else if (pooling_type == "avg") { + math::Pool2x2Avg(strides, paddings, in_x, out); + } + + } else { + PoolBasic(pooling_type, ksize, strides, paddings, in_x, out); + } +} + +} // namespace operators +} // namespace paddle_mobile +#endif diff --git a/src/operators/kernel/central-arm-func/sigmoid_arm_func.h b/src/operators/kernel/central-arm-func/sigmoid_arm_func.h new file mode 100644 index 0000000000..eb0e4ab7e4 --- /dev/null +++ b/src/operators/kernel/central-arm-func/sigmoid_arm_func.h @@ -0,0 +1,82 @@ +/* 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. */ +#ifdef SIGMOID_OP +#pragma once + +#include "operators/op_param.h" +#if __ARM_NEON +#include +#include "operators/math/math_func_neon.h" +#endif + +namespace paddle_mobile { +namespace operators { +using framework::DDim; +void sigmoid(const Tensor *X, Tensor *Y) { +#if __ARM_NEON + const float *input = X->data(); + float *output = Y->mutable_data(); + const DDim &dDim = X->dims(); + int axis_index = 1; + if (dDim.size() < 4) { + axis_index = 0; + } + DDim outer_ddim = + paddle_mobile::framework::slice_ddim(dDim, 0, axis_index + 1); + DDim inner_ddim = + paddle_mobile::framework::slice_ddim(dDim, axis_index + 1, dDim.size()); + int out_size = paddle_mobile::framework::product(outer_ddim); + int inner_size = paddle_mobile::framework::product(inner_ddim); + + DLOG << "outsize=" << out_size; + DLOG << "innersize=" << inner_size; + #pragma omp parallel for + for (int i = 0; i < out_size; ++i) { + const float *input_outer_ptr = input + i * inner_size; + float *output_outer_ptr = output + i * inner_size; + int nn = inner_size >> 2; + int remain = inner_size - (nn << 2); + float32x4_t _one = vdupq_n_f32(1.f); + for (; nn > 0; nn--) { + float32x4_t data = vld1q_f32(input_outer_ptr); + data = vnegq_f32(data); + data = exp_ps(data); + data = vaddq_f32(data, _one); + float32x4_t out_data = vrecpeq_f32(data); + out_data = vmulq_f32(vrecpsq_f32(data, out_data), out_data); + vst1q_f32(output_outer_ptr, out_data); + + input_outer_ptr += 4; + output_outer_ptr += 4; + } + for (; remain > 0; remain--) { + *output_outer_ptr = 1.f / (1.f + exp(-*input_outer_ptr)); + output_outer_ptr++; + input_outer_ptr++; + } + } +#endif +} + +template +void SigmoidCompute(const SigmoidParam ¶m) { + const Tensor *in_x = param.InputX(); + Tensor *out = param.Out(); + auto x_dims = in_x->dims(); + out->Resize(x_dims); + sigmoid(in_x, out); +} +} // namespace operators +} // namespace paddle_mobile +#endif diff --git a/src/operators/kernel/central-arm-func/softmax_arm_func.h b/src/operators/kernel/central-arm-func/softmax_arm_func.h new file mode 100644 index 0000000000..5a60bf88ae --- /dev/null +++ b/src/operators/kernel/central-arm-func/softmax_arm_func.h @@ -0,0 +1,30 @@ +/* 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. */ + +#ifdef SOFTMAX_OP +#pragma once +#include "../../math/softmax.h" +namespace paddle_mobile { +namespace operators { +template +void SoftmaxCompute(const SoftmaxParam ¶m) { + const Tensor *in_x = param.InputX(); + Tensor *out = param.Out(); + auto x_dims = in_x->dims(); + out->Resize(x_dims); + math::SoftmaxFuntor()(in_x, out); +} +} // namespace operators +} // namespace paddle_mobile +#endif diff --git a/src/operators/kernel/pool_kernel.h b/src/operators/kernel/pool_kernel.h index d666910b73..fd9faa3d5a 100644 --- a/src/operators/kernel/pool_kernel.h +++ b/src/operators/kernel/pool_kernel.h @@ -17,7 +17,6 @@ limitations under the License. */ #pragma once #include "framework/operator.h" -#include "operators/math/pooling.h" #include "operators/op_param.h" namespace paddle_mobile { diff --git a/src/operators/kernel/softmax_kernel.h b/src/operators/kernel/softmax_kernel.h index 5a87d64dd9..a500d9c81c 100644 --- a/src/operators/kernel/softmax_kernel.h +++ b/src/operators/kernel/softmax_kernel.h @@ -23,8 +23,6 @@ namespace paddle_mobile { namespace operators { using framework::OpKernelBase; -void simoid(Tensor *X, Tensor *Y); - template class SoftmaxKernel : public OpKernelBase { public: diff --git a/src/operators/math/depthwise_conv_3x3.cpp b/src/operators/math/depthwise_conv_3x3.cpp index 984678e873..f23affb451 100644 --- a/src/operators/math/depthwise_conv_3x3.cpp +++ b/src/operators/math/depthwise_conv_3x3.cpp @@ -245,7 +245,10 @@ void DepthwiseConv3x3s1p1(const Tensor *input, const Tensor *filter, const float *input_data = input->data(); const float *filter_data = filter->data(); float *output_data = output->data(); - const float *bias_data = bias->data(); + const float *bias_data; + if (if_bias) { + bias_data = bias->data(); + } const int h = static_cast(input->dims()[2]); const int w = static_cast(input->dims()[3]); diff --git a/src/operators/math/pool_3x3.cpp b/src/operators/math/pool_3x3.cpp index fb91528b47..83d0bcb699 100644 --- a/src/operators/math/pool_3x3.cpp +++ b/src/operators/math/pool_3x3.cpp @@ -13,9 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. */ #ifdef POOL_OP -#include "operators/math/pool_3x3.h" -#include +#include "pool_3x3.h" #include "framework/tensor.h" +#if __ARM_NEON +#include +#endif // __ARM_NEON +#include namespace paddle_mobile { namespace operators { namespace math { diff --git a/src/operators/op_param.h b/src/operators/op_param.h index c0f0fbc8a9..892b08e6da 100644 --- a/src/operators/op_param.h +++ b/src/operators/op_param.h @@ -195,8 +195,7 @@ class OpParam { class ConvParam : OpParam { public: ConvParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { + const AttributeMap &attrs, const Scope &scope) { filter_ = FilterFrom(inputs, scope); input_ = InputFrom(inputs, scope); output_ = OutputFrom(outputs, scope); @@ -237,12 +236,11 @@ Print &operator<<(Print &printer, 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); + const VariableNameMap &outputs, const AttributeMap &attrs, + const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + input_y_ = InputYFrom(inputs, scope); + out_ = OutFrom(outputs, scope); axis_ = GetAttr("axis", attrs); } @@ -267,11 +265,10 @@ class ElementwiseAddParam : OpParam { 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); + const AttributeMap &attrs, const 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); } @@ -299,10 +296,9 @@ class MulParam : OpParam { class ConcatParam : public OpParam { public: ConcatParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { + const AttributeMap &attrs, const Scope &scope) { inputs_ = InputMultiFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + out_ = OutFrom(outputs, scope); axis_ = GetAttr("axis", attrs); } @@ -323,11 +319,10 @@ class ConcatParam : public OpParam { class LrnParam : public OpParam { public: LrnParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); - mid_out_ = MidOutFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); + mid_out_ = MidOutFrom(outputs, scope); n_ = GetAttr("n", attrs); alpha_ = GetAttr("alpha", attrs); beta_ = GetAttr("beta", attrs); @@ -367,14 +362,13 @@ class LrnParam : public OpParam { class BatchNormParam : OpParam { public: BatchNormParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - output_y_ = OutputYFrom(outputs, scope); - input_bias_ = InputBiasFrom(inputs, scope); - input_mean_ = InputMeanFrom(inputs, scope); - input_scale_ = InputScaleFrom(inputs, scope); - input_variance_ = InputVarianceFrom(inputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + output_y_ = OutputYFrom(outputs, scope); + input_bias_ = InputBiasFrom(inputs, scope); + input_mean_ = InputMeanFrom(inputs, scope); + input_scale_ = InputScaleFrom(inputs, scope); + input_variance_ = InputVarianceFrom(inputs, scope); epsilon_ = GetAttr("epsilon", attrs); momentum_ = GetAttr("momentum", attrs); is_test_ = GetAttr("is_test", attrs); @@ -418,11 +412,10 @@ class BatchNormParam : OpParam { class PoolParam : public OpParam { public: PoolParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_ = InputXFrom(inputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_ = InputXFrom(inputs, scope); - output_ = OutFrom(outputs, scope); + output_ = OutFrom(outputs, scope); pooling_type_ = GetAttr("pooling_type", attrs); ksize_ = GetAttr>("ksize", attrs); strides_ = GetAttr>("strides", attrs); @@ -464,13 +457,11 @@ class PoolParam : public OpParam { class PriorBoxParam : public OpParam { public: PriorBoxParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_ = InputFrom(inputs, scope); - input_image_ = InputImageFrom(inputs, scope); - output_boxes_ = OutputBoxesFrom(outputs, scope); - output_variances_ = - OutputVariancesFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_ = InputFrom(inputs, scope); + input_image_ = InputImageFrom(inputs, scope); + output_boxes_ = OutputBoxesFrom(outputs, scope); + output_variances_ = OutputVariancesFrom(outputs, scope); min_sizes_ = GetAttr>("min_sizes", attrs); max_sizes_ = GetAttr>("max_sizes", attrs); aspect_ratios_ = GetAttr>("aspect_ratios", attrs); @@ -528,13 +519,11 @@ class PriorBoxParam : public OpParam { class BoxCoderParam : public OpParam { public: BoxCoderParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_priorbox_ = InputPriorBoxFrom(inputs, scope); - input_priorboxvar_ = - InputPriorBoxVarFrom(inputs, scope); - input_targetbox_ = InputTargetBoxFrom(inputs, scope); - output_box_ = OutputBoxFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_priorbox_ = InputPriorBoxFrom(inputs, scope); + input_priorboxvar_ = InputPriorBoxVarFrom(inputs, scope); + input_targetbox_ = InputTargetBoxFrom(inputs, scope); + output_box_ = OutputBoxFrom(outputs, scope); code_type_ = GetAttr("code_type", attrs); } const Tensor *InputPriorBox() const { return input_priorbox_; } @@ -560,10 +549,9 @@ class BoxCoderParam : public OpParam { class SoftmaxParam : public OpParam { public: SoftmaxParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); } const Tensor *InputX() const { return input_x_; } Tensor *Out() const { return out_; } @@ -578,10 +566,9 @@ class SoftmaxParam : public OpParam { class SigmoidParam : public OpParam { public: SigmoidParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); } const Tensor *InputX() const { return input_x_; } Tensor *Out() const { return out_; } @@ -643,9 +630,9 @@ class MultiClassNMSParam : public OpParam { class FeedParam : public OpParam { public: FeedParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + const AttributeMap &attrs, Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); auto var = scope.Var("batch_size"); batch_size = var->GetValue(); } @@ -662,10 +649,9 @@ class FeedParam : public OpParam { class FetchParam : public OpParam { public: FetchParam(const VariableNameMap &inputs, const VariableNameMap &outputs, - const framework::AttributeMap &attrs, - const framework::Scope &scope) { - input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + const AttributeMap &attrs, const Scope &scope) { + input_x_ = InputXFrom(inputs, scope); + out_ = OutFrom(outputs, scope); } const Tensor *InputX() const { return input_x_; } Tensor *Out() const { return out_; } @@ -863,10 +849,10 @@ class FusionConvAddBNReluParam : public OpParam { paddings_ = GetAttr>("paddings", attrs); dilations_ = GetAttr>("dilations", attrs); groups = GetAttr("groups", attrs); - input_bias_ = InputBiasFrom(inputs, scope); - input_mean_ = InputMeanFrom(inputs, scope); - input_scale_ = InputScaleFrom(inputs, scope); - input_variance_ = InputVarianceFrom(inputs, scope); + input_bias_ = InputBiasFrom(inputs, scope); + input_mean_ = InputMeanFrom(inputs, scope); + input_scale_ = InputScaleFrom(inputs, scope); + input_variance_ = InputVarianceFrom(inputs, scope); epsilon_ = GetAttr("epsilon", attrs); momentum_ = GetAttr("momentum", attrs); is_test_ = GetAttr("is_test", attrs); diff --git a/test/net/test_googlenet.cpp b/test/net/test_googlenet.cpp index c6b99a2ed0..1695995a8d 100644 --- a/test/net/test_googlenet.cpp +++ b/test/net/test_googlenet.cpp @@ -17,25 +17,25 @@ limitations under the License. */ #include "../test_include.h" int main() { - paddle_mobile::PaddleMobile paddle_mobile; + paddle_mobile::Loader loader; bool optimize = true; auto time1 = time(); // auto program = loader.Load(g_googlenet, optimize); - if (paddle_mobile.Load(g_googlenet_combine + "/model", - g_googlenet_combine + "/params", optimize)) { - auto time2 = time(); - DLOG << "load cost :" << time_diff(time1, time2) << "ms\n"; - std::vector input; - std::vector dims{1, 3, 224, 224}; - GetInput(g_test_image_1x3x224x224, &input, dims); - auto time3 = time(); + auto program = loader.Load(g_googlenet_combine + "/model", + g_googlenet_combine + "/params", optimize); + auto time2 = time(); + DLOG << "load cost :" << time_diff(time1, time2) << "ms\n"; + paddle_mobile::Executor executor(program, 1, optimize); + std::vector input; + std::vector dims{1, 3, 224, 224}; + GetInput(g_test_image_1x3x224x224, &input, dims); + auto time3 = time(); - for (int i = 0; i < 10; ++i) { - paddle_mobile.Predict(input, dims); - } - - auto time4 = time(); - DLOG << "predict cost :" << time_diff(time3, time4) << "ms\n"; + for (int i = 0; i < 10; ++i) { + executor.Predict(input, dims); } + + auto time4 = time(); + DLOG << "predict cost :" << time_diff(time3, time4) << "ms\n"; return 0; } diff --git a/tools/build.sh b/tools/build.sh index 80caa40118..43ce4eb636 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -32,8 +32,8 @@ build_for_mac() { build_for_android() { #rm -rf "../build" - if [ -z "${ANDROID_NDK}" ]; then - echo "ANDROID_NDK not found!" + if [ -z "${NDK_ROOT}" ]; then + echo "NDK_ROOT not found!" exit -1 fi -- GitLab