From d1d70ec8319a55964231f2e925ef8cb881c94497 Mon Sep 17 00:00:00 2001 From: wanghaoshuang Date: Thu, 22 Jun 2017 16:54:07 +0800 Subject: [PATCH] Refine configure option of crop layer 1. change configure content to 'axis, offset, shape' 2. add an optional input to crop layer as cropping reference --- paddle/function/CropOp.cpp | 63 ++++++++++++--------------- paddle/function/CropOp.h | 15 ++----- paddle/function/CropOpGpu.cu | 32 ++++++++------ paddle/function/CropOpTest.cpp | 4 +- paddle/gserver/layers/CropLayer.cpp | 67 ++++++++++++++++++++++------- paddle/gserver/layers/CropLayer.h | 13 ++++-- 6 files changed, 114 insertions(+), 80 deletions(-) diff --git a/paddle/function/CropOp.cpp b/paddle/function/CropOp.cpp index 4d47d9c149c..0d511ceef5e 100644 --- a/paddle/function/CropOp.cpp +++ b/paddle/function/CropOp.cpp @@ -17,28 +17,27 @@ limitations under the License. */ #include "paddle/function/TensorShape.h" namespace paddle { -static inline CropConf castToCropConf(const FuncConfig& conf) { - return {conf.get>("crop_corner"), - conf.get>("crop_shape")}; -} - template <> void Crop(real* outputs, const real* inputs, const TensorShape inShape, - const CropConf& crop) { - int cCrop = crop.corner[0]; - int hCrop = crop.corner[1]; - int wCrop = crop.corner[2]; + const FuncConfig& conf) { + std::vector crop_corner = + conf.get>("crop_corner"); + std::vector crop_shape = + conf.get>("crop_shape"); + int cCrop = crop_corner[1]; + int hCrop = crop_corner[2]; + int wCrop = crop_corner[3]; int num = inShape[0]; int inC = inShape[1]; int inH = inShape[2]; int inW = inShape[3]; - int outC = crop.shape[0]; - int outH = crop.shape[1]; - int outW = crop.shape[2]; + int outC = crop_shape[1]; + int outH = crop_shape[2]; + int outW = crop_shape[3]; for (int n = 0; n < num; n++) { for (int c = 0; c < outC; c++) { @@ -55,19 +54,23 @@ template <> void CropGrad(const real* inGrad, real* outGrad, const TensorShape outShape, - const CropConf& crop) { - int cCrop = crop.corner[0]; - int hCrop = crop.corner[1]; - int wCrop = crop.corner[2]; + const FuncConfig& conf) { + std::vector crop_corner = + conf.get>("crop_corner"); + std::vector crop_shape = + conf.get>("crop_shape"); + int cCrop = crop_corner[1]; + int hCrop = crop_corner[2]; + int wCrop = crop_corner[3]; int num = outShape[0]; int outC = outShape[1]; int outH = outShape[2]; int outW = outShape[3]; - int inC = crop.shape[0]; - int inH = crop.shape[1]; - int inW = crop.shape[2]; + int inC = crop_shape[1]; + int inH = crop_shape[2]; + int inW = crop_shape[3]; for (int n = 0; n < num; n++) { for (int c = 0; c < inC; c++) { @@ -111,26 +114,21 @@ void CropGrad(const real* inGrad, template class CropFunc : public FunctionBase { public: - void init(const FuncConfig& config) override { - crop_ = castToCropConf(config); - } + void init(const FuncConfig& config) override { conf_ = config; } void calc(const BufferArgs& inputs, const BufferArgs& outputs) override { CHECK_EQ(1UL, inputs.size()); CHECK_EQ(1UL, outputs.size()); - CHECK_EQ(outputs[0].shape()[1], crop_.shape[0]); - CHECK_EQ(outputs[0].shape()[2], crop_.shape[1]); - CHECK_EQ(outputs[0].shape()[3], crop_.shape[2]); CHECK_EQ(outputs[0].getArgType(), ASSIGN_TO); TensorShape inShape = inputs[0].shape(); Crop( - outputs[0].data(), inputs[0].data(), inShape, crop_); + outputs[0].data(), inputs[0].data(), inShape, conf_); } private: - CropConf crop_; + FuncConfig conf_; }; /** @@ -145,26 +143,21 @@ private: template class CropGradFunc : public FunctionBase { public: - void init(const FuncConfig& config) override { - crop_ = castToCropConf(config); - } + void init(const FuncConfig& config) override { conf_ = config; } void calc(const BufferArgs& inputs, const BufferArgs& outputs) override { CHECK_EQ(1UL, inputs.size()); CHECK_EQ(1UL, outputs.size()); - CHECK_EQ(inputs[0].shape()[1], crop_.shape[0]); - CHECK_EQ(inputs[0].shape()[2], crop_.shape[1]); - CHECK_EQ(inputs[0].shape()[3], crop_.shape[2]); CHECK_EQ(outputs[0].getArgType(), ASSIGN_TO); TensorShape outShape = outputs[0].shape(); CropGrad( - inputs[0].data(), outputs[0].data(), outShape, crop_); + inputs[0].data(), outputs[0].data(), outShape, conf_); } private: - CropConf crop_; + FuncConfig conf_; }; REGISTER_TYPED_FUNC(Crop, CPU, CropFunc); diff --git a/paddle/function/CropOp.h b/paddle/function/CropOp.h index 78a55bd43e9..71e8c4c00ee 100644 --- a/paddle/function/CropOp.h +++ b/paddle/function/CropOp.h @@ -18,13 +18,6 @@ limitations under the License. */ namespace paddle { -struct CropConf { - /// The upper left corner of croped result - std::vector corner; - /// The shape of croped result - std::vector shape; -}; - /** * \brief This funtion crops inputs according to the specify start point and *shape. @@ -32,13 +25,13 @@ struct CropConf { * \param[out] outputs save results. * \param[in] inputs input data. * \param[in] inShape the shape of input tensor. - * \param[in] crop the cropping config + * \param[in] conf the cropping config */ template void Crop(real* outputs, const real* inputs, const TensorShape inShape, - const CropConf& crop); + const FuncConfig& conf); /** * \brief Cropping operation backward. @@ -46,11 +39,11 @@ void Crop(real* outputs, * \param[out] inGrad gradients of previous layer * \param[in] outGrad output gradient * \param[in] inShape the shape of input tensor. - * \param[in] crop the cropping config + * \param[in] conf the cropping config */ template void CropGrad(const real* inGrad, real* outGrad, const TensorShape inShape, - const CropConf& crop); + const FuncConfig& conf); } // namespace paddle diff --git a/paddle/function/CropOpGpu.cu b/paddle/function/CropOpGpu.cu index f7d7d03abd2..cadb58b6e99 100644 --- a/paddle/function/CropOpGpu.cu +++ b/paddle/function/CropOpGpu.cu @@ -37,19 +37,21 @@ template <> void Crop(real* outputs, const real* inputs, const TensorShape inShape, - const CropConf& crop) { - int cropC = crop.corner[0]; - int cropH = crop.corner[1]; - int cropW = crop.corner[2]; + const FuncConfig& conf) { + std::vector crop_corner = conf.get>("crop_corner"); + std::vector crop_shape = conf.get>("crop_shape"); + int cropC = crop_corner[1]; + int cropH = crop_corner[2]; + int cropW = crop_corner[3]; int num = inShape[0]; int inC = inShape[1]; int inH = inShape[2]; int inW = inShape[3]; - int outC = crop.shape[0]; - int outH = crop.shape[1]; - int outW = crop.shape[2]; + int outC = crop_shape[1]; + int outH = crop_shape[2]; + int outW = crop_shape[3]; size_t nth = num * outC * outH * outW; int blockSize = 1024; @@ -82,19 +84,21 @@ template <> void CropGrad(const real* inGrad, real* outGrad, const TensorShape outShape, - const CropConf& crop) { - int cropC = crop.corner[0]; - int cropH = crop.corner[1]; - int cropW = crop.corner[2]; + const FuncConfig& conf) { + std::vector crop_corner = conf.get>("crop_corner"); + std::vector crop_shape = conf.get>("crop_shape"); + int cropC = crop_corner[1]; + int cropH = crop_corner[2]; + int cropW = crop_corner[3]; int num = outShape[0]; int outC = outShape[1]; int outH = outShape[2]; int outW = outShape[3]; - int inC = crop.shape[0]; - int inH = crop.shape[1]; - int inW = crop.shape[2]; + int inC = crop_shape[1]; + int inH = crop_shape[2]; + int inW = crop_shape[3]; size_t nth = num * inC * inH * inW; int blockSize = 1024; diff --git a/paddle/function/CropOpTest.cpp b/paddle/function/CropOpTest.cpp index 62b4bd9fdea..c331a70d1f6 100644 --- a/paddle/function/CropOpTest.cpp +++ b/paddle/function/CropOpTest.cpp @@ -28,8 +28,8 @@ TEST(Crop, real) { FunctionCompare compare( test_grad ? "CropGrad" : "Crop", FuncConfig() - .set>("crop_corner", {1, 1, 1}) - .set>("crop_shape", {2, 3, 3})); + .set>("crop_corner", {0, 1, 1, 1}) + .set>("crop_shape", {0, 2, 3, 3})); TensorShape inDims{numSamples, channels, imgSizeH, imgSizeW}; TensorShape outDims{numSamples, 2, 3, 3}; compare.addInputs( diff --git a/paddle/gserver/layers/CropLayer.cpp b/paddle/gserver/layers/CropLayer.cpp index ab23d4617e3..198ceffb463 100644 --- a/paddle/gserver/layers/CropLayer.cpp +++ b/paddle/gserver/layers/CropLayer.cpp @@ -25,20 +25,57 @@ bool CropLayer::init(const LayerMap& layerMap, Layer::init(layerMap, parameterMap); auto& crop_conf = config_.inputs(0).crop_conf(); - auto& img_conf = crop_conf.image_conf(); - CHECK_EQ(config_.inputs_size(), 1); - inDims_ = TensorShape( - {0, - img_conf.channels(), - img_conf.has_img_size_y() ? img_conf.img_size_y() : img_conf.img_size(), - img_conf.img_size()}); - - crop_corner_ = {crop_conf.crop_corner(0), - crop_conf.crop_corner(1), - crop_conf.crop_corner(2)}; - crop_shape_ = {crop_conf.crop_shape(0), - crop_conf.crop_shape(1), - crop_conf.crop_shape(2)}; + crop_axis_ = crop_conf.axis(); + for (int i = 0; i < crop_conf.offset_size(); i++) { + crop_offsets_[i] = crop_conf.offset(i); + } + + // 1. get input_0 shape + auto& input0_img_conf = config_.inputs(0).image_conf(); + inDims_ = TensorShape({0, + input0_img_conf.channels(), + input0_img_conf.has_img_size_y() + ? input0_img_conf.img_size_y() + : input0_img_conf.img_size(), + input0_img_conf.img_size()}); + + // 2. get output shape from input_1 or crop shap conf + if (config_.inputs_size() == 2) { + auto& input1_img_conf = config_.inputs(1).image_conf(); + targetDims_ = TensorShape({0, + input1_img_conf.channels(), + input1_img_conf.has_img_size_y() + ? input1_img_conf.img_size_y() + : input1_img_conf.img_size(), + input1_img_conf.img_size()}); + } else { + targetDims_ = TensorShape({crop_conf.shape(0), + crop_conf.shape(1), + crop_conf.shape(2), + crop_conf.shape(3)}); + } + + // 3. get final crop shape + int dimSize = 4; + for (int i = 0; i < dimSize; i++) { + if (i >= crop_axis_) { + crop_shape_[i] = targetDims_[i]; + } else { + crop_shape_[i] = inDims_[i]; + } + } + + // 4. get final crop corner + crop_corner_ = {0, 0, 0, 0}; + for (int i = 0; i < dimSize; i++) { + if (i >= crop_axis_) { + if (crop_offsets_.size() > 1) { + crop_corner_[i] = crop_offsets_[i - crop_axis_]; + } else { + crop_corner_[i] = crop_offsets_[0]; + } + } + } outDims_ = TensorShape(4); setOutDims(0); @@ -58,7 +95,7 @@ bool CropLayer::init(const LayerMap& layerMap, } void CropLayer::setOutDims(const size_t batchSize) { - outDims_.reshape({batchSize, crop_shape_[0], crop_shape_[1], crop_shape_[2]}); + outDims_.reshape({batchSize, crop_shape_[1], crop_shape_[2], crop_shape_[3]}); } void CropLayer::setTensorDim(const size_t batchSize) { diff --git a/paddle/gserver/layers/CropLayer.h b/paddle/gserver/layers/CropLayer.h index 3ce89707caf..23cede1c3fe 100644 --- a/paddle/gserver/layers/CropLayer.h +++ b/paddle/gserver/layers/CropLayer.h @@ -19,9 +19,13 @@ limitations under the License. */ namespace paddle { /** - * \brief This layer crop inputs according to the specify corner and shape. - * The input and output is a 4D tensor. Cropping from the 2nd to - * the 4th dimenstion. + * \brief This layer crop input according to the specify conf. + * input_0: input to be cropped + * input_1: optional reference input + * axis: start dimension to be croped + * offset: offset of cropping in each dimension + * shape: if reference input layer was not setted, + * crop input as this shape conf */ class CropLayer : public Layer { public: @@ -38,9 +42,12 @@ protected: void setOutDims(const size_t batchSize); void setTensorDim(const size_t batchSize); + int32_t crop_axis_; + std::vector crop_offsets_; std::vector crop_corner_; std::vector crop_shape_; TensorShape inDims_; + TensorShape targetDims_; TensorShape outDims_; }; } // namespace paddle -- GitLab