diff --git a/src/framework/operator.cpp b/src/framework/operator.cpp index a5ec5e8a333fb6a9ecfc04695a4155213db9e810..7c66f932df3df9793f116c8e62fea704e346b146 100644 --- a/src/framework/operator.cpp +++ b/src/framework/operator.cpp @@ -59,6 +59,7 @@ template void OperatorBase::Run() const { RunImpl(); #ifdef PADDLE_MOBILE_DEBUG + DLOG << "-------------" << type_ << "----------------------------"; vector input_keys = GetInputKeys(); for (const auto key : input_keys) { Tensor *input = GetVarValue(key, inputs_, *scope_); diff --git a/src/io/executor.cpp b/src/io/executor.cpp index 4b92ce0829ce23426406b88783f6e232e33445b0..562ba92adbfc5862c67b33bf5dab323f33768480 100644 --- a/src/io/executor.cpp +++ b/src/io/executor.cpp @@ -73,6 +73,7 @@ Executor::Executor(const framework::Program p, int batch_size, #ifdef PADDLE_EXECUTOR_MULTITHREAD depManager.resize(blocks.size()); #endif + DLOG << "executer in loaddable mode: " << loddable_; for (int i = 0; i < blocks.size(); ++i) { std::shared_ptr block_desc = blocks[i]; std::vector> ops = block_desc->Ops(); @@ -82,7 +83,6 @@ Executor::Executor(const framework::Program p, int batch_size, auto op_base = framework::OpRegistry::CreateOp( op->Type(), op->GetInputs(), op->GetOutputs(), op->GetAttrMap(), program_.scope); - DLOG << "executer in loaddable mode: " << loddable_; // use pre_infershape to pre resize , but if u use an lod mode tensor u // need to resize in runtime if (!loddable_) { @@ -176,6 +176,7 @@ void Executor::LoadMemory(const framework::VarDesc var_desc, type_size = 8; break; case framework::VARTYPE_TYPE_INT32: + memory = tensor->mutable_data(); type_size = 4; break; case framework::VARTYPE_TYPE_INT64: @@ -308,6 +309,9 @@ bool Executor::varInputMemory( } case framework::VARTYPE_TYPE_INT32: { + tensor = var->template GetMutable(); + tensor->template mutable_data(); + is_mute_match = true; break; } diff --git a/src/operators/bilinear_interp_op.cpp b/src/operators/bilinear_interp_op.cpp index 319cc2cea68ade29e192d45a98f64d6c7d5601ed..b3388c38ec6050faff1cb7bbe49e8dd042291fc9 100644 --- a/src/operators/bilinear_interp_op.cpp +++ b/src/operators/bilinear_interp_op.cpp @@ -20,8 +20,25 @@ namespace paddle_mobile { namespace operators { template void BilinearOp::InferShape() const { - // todo check - this->param_.Out()->Resize(this->param_.InputX()->dims()); + PADDLE_MOBILE_ENFORCE(this->param_.InputX() != nullptr, + "Input(X) of BilinearInterOp should not be null."); + PADDLE_MOBILE_ENFORCE(this->param_.Out() != nullptr, + "Output(Out) of BilinearInterOp should not be null."); + + auto dim_x = this->param_.InputX()->dims(); // NCHW format + int out_h = this->param_.OutH(); + int out_w = this->param_.OutW(); + PADDLE_MOBILE_ENFORCE(dim_x.size() == 4, "X's dimension must be 4"); + + if (this->param_.InputOutPutSize() != nullptr) { + auto out_size_dim = this->param_.InputOutPutSize()->dims(); + + PADDLE_MOBILE_ENFORCE(out_size_dim.size() == 1, + "OutSize's dimension size must be 1"); + PADDLE_MOBILE_ENFORCE(out_size_dim[0] == 2, "OutSize's dim[0] must be 2"); + } + std::vector dim_out({dim_x[0], dim_x[1], out_h, out_w}); + this->param_.Out()->Resize(framework::make_ddim(dim_out)); } } // namespace operators diff --git a/src/operators/flatten_op.cpp b/src/operators/flatten_op.cpp index ebc0e4c526696b0cd62a241850dd13deeb271b33..0282414ca6ed0be743849e9d295a354144fccdb9 100644 --- a/src/operators/flatten_op.cpp +++ b/src/operators/flatten_op.cpp @@ -18,10 +18,32 @@ limitations under the License. */ namespace paddle_mobile { namespace operators { + template void FlattenOp::InferShape() const { - // todo check - this->param_.Out()->Resize(this->param_.InputX()->dims()); + PADDLE_MOBILE_ENFORCE(this->param_.InputX() != nullptr, + "Input (X) of Flatten op should not be null."); + PADDLE_MOBILE_ENFORCE(this->param_.Out() != nullptr, + "Output (Output) of Flatten op should not be null."); + + auto &axis = this->param_.Axis(); + PADDLE_MOBILE_ENFORCE(axis >= 0, + "The axis should be greater than or equal to 0."); + + auto &in_dims = this->param_.InputX()->dims(); + // const auto &in_dims = ctx->GetInputDim("X"); + PADDLE_MOBILE_ENFORCE( + axis <= in_dims.size(), + "The axis should be less than or equal to input tensor's rank."); + + const auto &out_dims = GetOutputShape(axis, in_dims); + this->param_.Out()->Resize(in_dims); + // todo supprot lodtensor + // if (in_dims[0] == out_dims[0]) { + // // Only pass LoD when the first dimension of output and Input(X) + // // are the same. + // ctx->ShareLoD("X", "Out"); + // } } } // namespace operators diff --git a/src/operators/flatten_op.h b/src/operators/flatten_op.h index 279f2e4aa3ff8efa6617bf9ee3bde7164c8a391a..4c1f6ff8a0f2b3212750f3be4d1a6aa2bad790ee 100644 --- a/src/operators/flatten_op.h +++ b/src/operators/flatten_op.h @@ -24,7 +24,21 @@ limitations under the License. */ namespace paddle_mobile { namespace operators { - +inline std::vector GetOutputShape(const int axis, + const framework::DDim &in_dims) { + int64_t outer = 1, inner = 1; + for (int i = 0; i < in_dims.size(); ++i) { + if (i < axis) { + outer *= in_dims[i]; + } else { + inner *= in_dims[i]; + } + } + std::vector out_shape(2); + out_shape[0] = static_cast(outer); + out_shape[1] = static_cast(inner); + return out_shape; +} using paddle_mobile::framework::Tensor; template diff --git a/src/operators/kernel/central-arm-func/bilinear_interp_arm_func.h b/src/operators/kernel/central-arm-func/bilinear_interp_arm_func.h index 068d33e46a8d425225bf9983c47829444a46f8af..3840985ab8a963eae7d9a4cf96d9a55acf38f68c 100644 --- a/src/operators/kernel/central-arm-func/bilinear_interp_arm_func.h +++ b/src/operators/kernel/central-arm-func/bilinear_interp_arm_func.h @@ -22,7 +22,68 @@ namespace paddle_mobile { namespace operators { template -void BilinearInterpCompute(const BilinearInterpParam& param) {} +void BilinearInterpCompute(const BilinearInterpParam& param) { + auto out_dims = param.Out()->dims(); + auto* input = param.InputX()->data(); + auto out_size_t = param.InputOutPutSize(); + + int out_h = param.OutH(); + int out_w = param.OutW(); + if (out_size_t != nullptr) { + auto out_size_data = out_size_t->data(); + out_h = out_size_data[0]; + out_w = out_size_data[1]; + } + auto* output = param.Out()->mutable_data( + {out_dims[0], out_dims[1], out_h, out_w}); + auto batch_size = param.InputX()->dims()[0]; + auto channels = param.InputX()->dims()[1]; + auto in_h = param.InputX()->dims()[2]; + auto in_w = param.InputX()->dims()[3]; + + auto in_hw = in_h * in_w; + auto out_hw = out_h * out_w; + auto in_chw = channels * in_hw; + auto out_chw = channels * out_hw; + + float ratio_h = + (out_h > 1) ? static_cast(in_h - 1) / (out_h - 1) : 0.f; + float ratio_w = + (out_w > 1) ? static_cast(in_w - 1) / (out_w - 1) : 0.f; + + if (in_h == out_h && in_w == out_w) { + memcpy(output, input, param.InputX()->numel() * sizeof(float)); + } else { + for (int k = 0; k < batch_size; ++k) { // loop for batches + for (int i = 0; i < out_h; ++i) { // loop for images + int h = ratio_h * i; + int hid = (h < in_h - 1) ? 1 : 0; + float h1lambda = ratio_h * i - h; + float h2lambda = 1.f - h1lambda; + + for (int j = 0; j < out_w; ++j) { + int w = ratio_w * j; + int wid = (w < in_w - 1) ? 1 : 0; + float w1lambda = ratio_w * j - w; + float w2lambda = 1.f - w1lambda; + // calculate four position for bilinear interpolation + const float* in_pos = &input[k * in_chw + h * in_w + w]; + float* out_pos = &output[k * out_chw + i * out_w + j]; + + for (int c = 0; c < channels; ++c) { // loop for channels + // bilinear interpolation + out_pos[0] = static_cast( + h2lambda * (w2lambda * in_pos[0] + w1lambda * in_pos[wid]) + + h1lambda * (w2lambda * in_pos[hid * in_w] + + w1lambda * in_pos[hid * in_w + wid])); + in_pos += in_hw; + out_pos += out_hw; + } + } + } + } + } +} } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/kernel/central-arm-func/flatten_arm_func.h b/src/operators/kernel/central-arm-func/flatten_arm_func.h index 526db3abd4a249531f3cccea62aad75722f5b4b0..8c803a20df10431dc54c00fc31fc17fcc8659d63 100644 --- a/src/operators/kernel/central-arm-func/flatten_arm_func.h +++ b/src/operators/kernel/central-arm-func/flatten_arm_func.h @@ -15,14 +15,29 @@ limitations under the License. */ #ifdef FLATTEN_OP #pragma once +#include #include +#include "operators/flatten_op.h" #include "operators/op_param.h" namespace paddle_mobile { namespace operators { template -void FlattenCompute(const FlattenParam& param) {} +void FlattenCompute(const FlattenParam ¶m) { + const auto *input_x = param.InputX(); + const auto axis = param.Axis(); + const auto &input_x_dims = input_x->dims(); + auto *out = param.Out(); + + const auto &out_shape_v = GetOutputShape(axis, input_x_dims); + const framework::DDim &out_dim = ValidateShape(out_shape_v, input_x_dims); + + out->Resize(out_dim); + out->mutable_data(); + framework::TensorCopy(*input_x, out); + out->Resize(out_dim); +} } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/kernel/central-arm-func/shape_arm_func.h b/src/operators/kernel/central-arm-func/shape_arm_func.h index 846f4c474ab067f02cfd809a876abc7b62ab784f..fa9154211fe24ff8e1cc4966f9684f1fbf5a3111 100644 --- a/src/operators/kernel/central-arm-func/shape_arm_func.h +++ b/src/operators/kernel/central-arm-func/shape_arm_func.h @@ -22,7 +22,15 @@ namespace paddle_mobile { namespace operators { template -void ShapeCompute(const ShapeParam& param) {} +void ShapeCompute(const ShapeParam& param) { + auto* in_t = param.Input(); + auto* out_t = param.Out(); + auto out_data = out_t->mutable_data(); + auto in_dims = in_t->dims(); + for (int i = 0; i < in_dims.size(); ++i) { + out_data[i] = static_cast(in_dims[i]); + } +} } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/kernel/central-arm-func/split_arm_func.h b/src/operators/kernel/central-arm-func/split_arm_func.h index 77c1c9ed55e042de91ed41ccbde1b3a01eebe212..24ab2f83a4f3be8b29cb9e33347d639c52f9eea1 100644 --- a/src/operators/kernel/central-arm-func/split_arm_func.h +++ b/src/operators/kernel/central-arm-func/split_arm_func.h @@ -21,8 +21,64 @@ limitations under the License. */ namespace paddle_mobile { namespace operators { +// Strided numel memory copy from src to dst by the specified axis +// +// For example, for a tensor dims [4, 20, 100], the strieded numel is +// [8000, 2000, 100] +// +// NOTE: The src and dst tensor should have the same elements +// except the specified axis. +template +inline void StridedNumelCopyWithAxis(int64_t axis, T* dst, + const framework::DDim& dst_stride_numel, + const T* src, + const framework::DDim& src_stride_numel, + int64_t size) { + int64_t before = dst_stride_numel[0] / dst_stride_numel[axis]; + int64_t src_after = src_stride_numel[axis]; + int64_t dst_after = dst_stride_numel[axis]; + + PADDLE_MOBILE_ENFORCE(src_stride_numel.size() == dst_stride_numel.size(), + "src and dst tensor should have the same dims size."); + + for (int64_t i = 0; i < axis; ++i) { + if (i < axis) { + PADDLE_MOBILE_ENFORCE(src_stride_numel[i] / src_stride_numel[axis] == + dst_stride_numel[i] / dst_stride_numel[axis], + "src and dst should have the same elements " + "except the specified axis."); + } else if (i == axis) { + continue; + } else { + PADDLE_MOBILE_ENFORCE(src_stride_numel[i] == dst_stride_numel[i], + "src and dst should have the same elements " + "except the specified axis."); + } + } + + for (int64_t i = 0; i < before; ++i) { + memory::Copy(dst + i * dst_after, src + i * src_after, sizeof(T) * size); + } +} + template -void SplitCompute(const SplitParam& param) {} +void SplitCompute(const SplitParam& param) { + auto* in = param.InputX(); + auto outs = param.Outs(); + auto in_stride = framework::stride_numel(in->dims()); + int64_t axis = param.Axis(); + + size_t input_offset = 0; + for (auto& out : outs) { + out->mutable_data(); + auto out_stride = framework::stride_numel(out->dims()); + + StridedNumelCopyWithAxis(axis, out->data(), out_stride, + in->data() + input_offset, in_stride, + out_stride[axis]); + input_offset += out_stride[axis]; + } +} } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/op_param.h b/src/operators/op_param.h index 5ceca937efe85e8ff06d5f1320f1018014a5bbc9..1728e6a6cc778ec223c3f14c971404ba3a5cc0f7 100644 --- a/src/operators/op_param.h +++ b/src/operators/op_param.h @@ -245,6 +245,12 @@ class OpParam { return GetVarValue("Out", outputs, scope); } + template + static vector OutMultiFrom(const VariableNameMap &outputs, + const Scope &scope) { + return GetMultiVarValue("Out", outputs, scope); + } + template static T *OutputYFrom(const VariableNameMap &outputs, const Scope &scope) { return GetVarValue("Y", outputs, scope); @@ -2248,13 +2254,16 @@ class FlattenParam : public OpParam { const AttributeMap &attrs, const Scope &scope) { input_x_ = InputXFrom(inputs, scope); out_ = OutFrom(outputs, scope); + axis = GetAttr("axis", attrs); } const RType *InputX() const { return input_x_; } RType *Out() const { return out_; } + const int &Axis() const { return axis; } private: RType *input_x_; RType *out_; + int axis; }; #endif @@ -2268,14 +2277,29 @@ class SplitParam : public OpParam { SplitParam(const VariableNameMap &inputs, const VariableNameMap &outputs, const AttributeMap &attrs, const Scope &scope) { input_x_ = InputXFrom(inputs, scope); - out_ = OutFrom(outputs, scope); + outs_ = OutMultiFrom(outputs, scope); + axis = GetAttr("axis", attrs); + num = GetAttr("num", attrs); + sections = GetAttr>("sections", attrs); + + // for (int i = 0; i < outs_.size(); ++i) { + // out_ts_.push_back(*scope.FindVar(outs_[i])->GetMutable()); + // } } const RType *InputX() const { return input_x_; } - RType *Out() const { return out_; } + std::vector Outs() const { return outs_; } + int Axis() const { return axis; } + int Num() const { return num; } + std::vector Sections() const { return sections; } + // std::vector OutTs() const { return out_ts_; } private: RType *input_x_; - RType *out_; + std::vector outs_; + int axis; + int num; + std::vector sections; + // std::vector out_ts_; }; #endif @@ -2292,14 +2316,21 @@ class BilinearInterpParam : public OpParam { input_x_ = InputXFrom(inputs, scope); input_outsize_ = InputOutSizeFrom(inputs, scope); out_ = OutFrom(outputs, scope); + out_h_ = GetAttr("out_h", attrs); + out_w_ = GetAttr("out_w", attrs); } const RType *InputX() const { return input_x_; } + const RType *InputOutPutSize() const { return input_outsize_; } RType *Out() const { return out_; } + int OutH() const { return out_h_; } + int OutW() const { return out_w_; } private: RType *input_x_; RType *input_outsize_; RType *out_; + int out_h_; + int out_w_; }; #endif @@ -2315,7 +2346,7 @@ class ShapeParam : public OpParam { input_ = InputFrom(inputs, scope); out_ = OutFrom(outputs, scope); } - const RType *InputX() const { return input_; } + const RType *Input() const { return input_; } RType *Out() const { return out_; } private: diff --git a/src/operators/shape_op.cpp b/src/operators/shape_op.cpp index ed91fd5d663ebb734051e3636aa5f95e3623e4d9..b50a9c4507bff31ee753980c93917b93a4e1f42f 100644 --- a/src/operators/shape_op.cpp +++ b/src/operators/shape_op.cpp @@ -20,7 +20,11 @@ namespace paddle_mobile { namespace operators { template void ShapeOp::InferShape() const { - this->param_.Out()->Resize(this->param_.InputX()->dims()); + PADDLE_MOBILE_ENFORCE(this->param_.Input() != nullptr, + "Input (Input) of get_shape op should not be null."); + PADDLE_MOBILE_ENFORCE(this->param_.Out() != nullptr, + "Output (Out) of get_shape op should not be null."); + this->param_.Out()->Resize({this->param_.Input()->dims().size()}); } } // namespace operators diff --git a/src/operators/split_op.cpp b/src/operators/split_op.cpp index df4c2b276cfd90fcf6fe3d29d4f80ae667ee17e1..8b7fadc1a64d1a6f7549e5875b543c871b385e6d 100644 --- a/src/operators/split_op.cpp +++ b/src/operators/split_op.cpp @@ -18,9 +18,62 @@ limitations under the License. */ namespace paddle_mobile { namespace operators { + template void SplitOp::InferShape() const { - this->param_.Out()->Resize(this->param_.InputX()->dims()); + PADDLE_MOBILE_ENFORCE(this->param_.InputX() != nullptr, + "Input(X) of SplitOp should not be null."); + // std::string str; + // str.size() + const auto &outs = this->param_.Outs(); + PADDLE_MOBILE_ENFORCE(outs.size() >= 1UL, + "Outputs(Out) of SplitOp should not be empty."); + + auto in_dims = this->param_.InputX()->dims(); + size_t axis = static_cast(this->param_.Axis()); + size_t num = static_cast(this->param_.Num()); + + const auto §ions = this->param_.Sections(); + + const size_t outs_number = outs.size(); + std::vector outs_dims; + outs_dims.reserve(outs_number); + + if (num > 0) { + int64_t in_axis_dim = in_dims[axis]; + PADDLE_MOBILE_ENFORCE(in_axis_dim % num == 0, + "tensor split does not result" + " in an equal division"); + size_t out_axis_dim = in_axis_dim / num; + for (size_t i = 0; i < outs_number; ++i) { + auto dim = in_dims; + dim[axis] = out_axis_dim; + outs_dims.push_back(dim); + } + } else if (sections.size() > 0) { + PADDLE_MOBILE_ENFORCE(sections.size() == outs_number, + "tensor split sections size" + "should be equal to output size."); + for (size_t i = 0; i < outs_number; ++i) { + auto dim = in_dims; + dim[axis] = sections[i]; + outs_dims.push_back(dim); + } + } + + PADDLE_MOBILE_ENFORCE(outs_dims.size() == outs.size(), + "length==dims.size() must be true!"); + for (int j = 0; j < outs_dims.size(); ++j) { + outs[j]->Resize(outs_dims[j]); + } + + // todo lod impl + // if (axis != 0) { + // // Only pass LoD when not spliting along the first dim. + // for (size_t i = 0; i < outs_number; ++i) { + // ctx->ShareLoD("X", "Out", 0, i); + // } + // } } } // namespace operators diff --git a/src/operators/split_op.h b/src/operators/split_op.h index 278b66d76cb5ed6cc02588602c64897260190bd1..f7d60b37441e77c5d47ac6040404535a841bcf8e 100644 --- a/src/operators/split_op.h +++ b/src/operators/split_op.h @@ -44,7 +44,6 @@ class SplitOp : public framework::OperatorWithKernel< operators::SplitKernel>::OperatorWithKernel; void InferShape() const override; }; - } // namespace operators } // namespace paddle_mobile diff --git a/test/net/test_mobilenet_025_fssd.cpp b/test/net/test_mobilenet_025_fssd.cpp index c1236d5bd6e91f17d7ded9b1709d52b9c3784aa6..ed27435a51a4aefee627149eff802121045d7c8c 100644 --- a/test/net/test_mobilenet_025_fssd.cpp +++ b/test/net/test_mobilenet_025_fssd.cpp @@ -23,7 +23,7 @@ int main() { // ../../../test/models/mobilenet auto time1 = time(); if (paddle_mobile.Load(std::string(g_fluid_fssd_new) + "/model", - std::string(g_fluid_fssd_new) + "/params", false)) { + std::string(g_fluid_fssd_new) + "/params", true)) { auto time2 = time(); std::cout << "load cost :" << time_diff(time1, time1) << "ms" << std::endl;