Skip to content

Commit 6b7f647

Browse files
author
wangyang59
committed
deconv projection/operator implementation
1 parent b8afb14 commit 6b7f647

File tree

8 files changed

+648
-259
lines changed

8 files changed

+648
-259
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#include "ConvBaseOperator.h"
16+
#include "paddle/math/MathUtils.h"
17+
#include "paddle/math/Matrix.h"
18+
19+
namespace paddle {
20+
21+
/**
22+
* @brief ConvBaseOperator takes two inputs to perform the convolution.
23+
* The first input is the image, and the second input is the convolution kernel.
24+
* The height of data for two inputs are the same. Each data of the first input
25+
* is convolved with each data of the second input indepedently.
26+
*
27+
* The config file api is conv_operator.
28+
*/
29+
30+
ConvBaseOperator::ConvBaseOperator(const OperatorConfig &config, bool useGpu)
31+
: Operator(config, useGpu) {
32+
CHECK(useGpu);
33+
CHECK_EQ(config_.input_indices_size(), 2L);
34+
35+
caffeMode_ = true;
36+
getConvParams();
37+
computeConvSizes();
38+
39+
// initialize all to default algorithms
40+
fwdAlgo_ = 0;
41+
bwdFilterAlgo_ = 0;
42+
bwdDataAlgo_ = 0;
43+
fwdLimitBytes_ = 0;
44+
bwdDataLimitBytes_ = 0;
45+
bwdFilterLimitBytes_ = 0;
46+
workSpaceInBytes_ = 0;
47+
workSpace_ = nullptr;
48+
49+
isSelectAlgo_ = false;
50+
}
51+
52+
void ConvBaseOperator::allocConvWorkSpace(size_t maxWorkSpace) {
53+
if (maxWorkSpace > workSpaceInBytes_) {
54+
if (workSpaceInBytes_ != 0) {
55+
hl_free_mem_device(workSpace_);
56+
}
57+
// total amount of storage needed
58+
workSpace_ = hl_malloc_device(maxWorkSpace);
59+
workSpaceInBytes_ = maxWorkSpace;
60+
}
61+
}
62+
63+
void ConvBaseOperator::reshape(int batchSize) {
64+
if (isDeconv_) {
65+
outputH_ = ins_[0]->getFrameHeight();
66+
outputW_ = ins_[0]->getFrameWidth();
67+
if (outputH_ == 0) outputH_ = outputY_;
68+
if (outputW_ == 0) outputW_ = outputX_;
69+
imageH_ =
70+
imageSize(outputH_, filterSizeY_, paddingY_, strideY_, caffeMode_);
71+
imageW_ = imageSize(outputW_, filterSize_, padding_, stride_, caffeMode_);
72+
/// Check that the imageSizes are consistent with config
73+
CHECK_EQ(imageH_, imgSizeY_);
74+
CHECK_EQ(imageW_, imgSize_);
75+
out_->setFrameHeight(imageH_);
76+
out_->setFrameWidth(imageW_);
77+
} else {
78+
imageH_ = ins_[0]->getFrameHeight();
79+
imageW_ = ins_[0]->getFrameWidth();
80+
if (imageH_ == 0) imageH_ = imgSizeY_;
81+
if (imageW_ == 0) imageW_ = imgSize_;
82+
outputH_ =
83+
outputSize(imageH_, filterSizeY_, paddingY_, strideY_, caffeMode_);
84+
outputW_ = outputSize(imageW_, filterSize_, padding_, stride_, caffeMode_);
85+
/// Check that the outputSizes are consistent with config
86+
CHECK_EQ(outputH_, outputY_);
87+
CHECK_EQ(outputW_, outputX_);
88+
out_->setFrameHeight(outputH_);
89+
out_->setFrameWidth(outputW_);
90+
}
91+
92+
reshapeImageDescriptors();
93+
94+
if (!isSelectAlgo_) {
95+
hl_conv_workspace(imageDesc_,
96+
outputDesc_,
97+
filterDesc_,
98+
convDesc_,
99+
&fwdAlgo_,
100+
&fwdLimitBytes_,
101+
&bwdDataAlgo_,
102+
&bwdDataLimitBytes_,
103+
&bwdFilterAlgo_,
104+
&bwdFilterLimitBytes_);
105+
106+
size_t maxWorkSpace = 0;
107+
maxWorkSpace = std::max(fwdLimitBytes_, bwdDataLimitBytes_);
108+
maxWorkSpace = std::max(maxWorkSpace, bwdFilterLimitBytes_);
109+
110+
allocConvWorkSpace(maxWorkSpace);
111+
}
112+
113+
isSelectAlgo_ = true;
114+
}
115+
116+
void ConvBaseOperator::computeConvSizes() {
117+
hl_create_filter_descriptor(
118+
&filterDesc_, channels_, numFilters_, filterSizeY_, filterSize_);
119+
hl_create_tensor_descriptor(&imageDesc_);
120+
hl_create_tensor_descriptor(&outputDesc_);
121+
hl_create_convolution_descriptor(&convDesc_,
122+
imageDesc_,
123+
filterDesc_,
124+
paddingY_,
125+
padding_,
126+
strideY_,
127+
stride_);
128+
}
129+
130+
void ConvBaseOperator::reshapeImageDescriptors() {
131+
hl_tensor_reshape(imageDesc_,
132+
1,
133+
channels_,
134+
imageH_,
135+
imageW_,
136+
channels_ * imageH_ * imageW_,
137+
imageH_ * imageW_,
138+
imageW_,
139+
1);
140+
hl_tensor_reshape(outputDesc_,
141+
1,
142+
numFilters_,
143+
outputH_,
144+
outputW_,
145+
numFilters_ * outputH_ * outputW_,
146+
outputH_ * outputW_,
147+
outputW_,
148+
1);
149+
hl_reset_convolution_descriptor(convDesc_,
150+
imageDesc_,
151+
filterDesc_,
152+
paddingY_,
153+
padding_,
154+
strideY_,
155+
stride_);
156+
157+
if (isDeconv_) {
158+
inputOffset_ = numFilters_ * outputH_ * outputW_;
159+
outputOffset_ = channels_ * imageH_ * imageW_;
160+
} else {
161+
inputOffset_ = channels_ * imageH_ * imageW_;
162+
outputOffset_ = numFilters_ * outputH_ * outputW_;
163+
}
164+
weightOffset_ = numFilters_ * channels_ * filterSize_ * filterSizeY_;
165+
}
166+
167+
void ConvBaseOperator::getConvParams() {
168+
configNumFilters_ = config_.num_filters();
169+
const ConvConfig &conf = config_.conv_conf();
170+
padding_ = conf.padding();
171+
stride_ = conf.stride();
172+
filterSize_ = conf.filter_size();
173+
paddingY_ = conf.padding_y();
174+
strideY_ = conf.stride_y();
175+
filterSizeY_ = conf.filter_size_y();
176+
filterPixels_ = filterSize_ * filterSizeY_;
177+
configChannels_ = conf.channels();
178+
imgSize_ = conf.img_size();
179+
imgSizeY_ = conf.has_img_size_y() ? conf.img_size_y() : conf.img_size();
180+
imgPixels_ = imgSize_ * imgSizeY_;
181+
CHECK_EQ(conf.groups(), 1U);
182+
filterChannels_ = conf.filter_channels();
183+
outputX_ = conf.output_x();
184+
outputY_ = conf.has_output_y() ? conf.output_y() : conf.output_x();
185+
outputs_ = outputX_ * outputX_;
186+
187+
isDeconv_ = (config_.type() == "conv") ? false : true;
188+
if (isDeconv_) {
189+
channels_ = configNumFilters_;
190+
numFilters_ = configChannels_;
191+
} else {
192+
channels_ = configChannels_;
193+
numFilters_ = configNumFilters_;
194+
}
195+
}
196+
197+
} // namespace paddle
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#include "Operator.h"
16+
#include "paddle/math/MathUtils.h"
17+
#include "paddle/math/Matrix.h"
18+
19+
namespace paddle {
20+
21+
/**
22+
* @brief ConvOperator takes two inputs to perform the convolution.
23+
* The first input is the image, and the second input is the convolution kernel.
24+
* The height of data for two inputs are the same. Each data of the first input
25+
* is convolved with each data of the second input indepedently.
26+
*
27+
* The config file api is conv_operator.
28+
*/
29+
30+
class ConvBaseOperator : public Operator {
31+
public:
32+
ConvBaseOperator(const OperatorConfig &config, bool useGpu);
33+
/**
34+
* Free workspace in device and destroy cudnn tensor descriptor.
35+
*/
36+
virtual ~ConvBaseOperator() {
37+
if (workSpaceInBytes_ != 0) {
38+
hl_free_mem_device(workSpace_);
39+
workSpaceInBytes_ = 0;
40+
}
41+
42+
hl_destroy_tensor_descriptor(imageDesc_);
43+
hl_destroy_tensor_descriptor(outputDesc_);
44+
hl_destroy_filter_descriptor(filterDesc_);
45+
hl_destroy_convolution_descriptor(convDesc_);
46+
}
47+
virtual void forward();
48+
virtual void backward();
49+
50+
private:
51+
/**
52+
* Get convolution parameters from layer config and
53+
* initialize member variables.
54+
*/
55+
void getConvParams();
56+
57+
/**
58+
* Allocate Gpu Memory for cudnn convolution algorithms.
59+
*/
60+
void allocConvWorkSpace(size_t maxWorkSpace);
61+
62+
/**
63+
* Create cudnn tensor descriptor for convolution operation.
64+
*/
65+
void computeConvSizes();
66+
67+
/**
68+
* Reshape cudnn tensor descriptor.
69+
*/
70+
void reshapeImageDescriptors();
71+
72+
/**
73+
* Reshape cudnn tensor descriptor.
74+
*/
75+
void reshape(int batchSize);
76+
77+
/**
78+
* Check filter size is equal to the size calculated by parameters from
79+
* layer config.
80+
*/
81+
void checkFilterSize(const MatrixPtr &filter) {
82+
CHECK_EQ(static_cast<int>(filter->getWidth()),
83+
filterSize_ * filterSizeY_ * channels_ * numFilters_);
84+
}
85+
86+
/// Most of member variables are same with CudnnConvLayer.
87+
/// There is no explanation here.
88+
bool isDeconv_;
89+
int imageH_, imageW_, outputH_, outputW_;
90+
hl_tensor_descriptor imageDesc_;
91+
hl_tensor_descriptor outputDesc_;
92+
hl_filter_descriptor filterDesc_;
93+
hl_convolution_descriptor convDesc_;
94+
bool caffeMode_;
95+
int inputOffset_, outputOffset_, weightOffset_;
96+
int numFilters_, channels_;
97+
98+
/// from parsing config
99+
int configNumFilters_, configChannels_;
100+
int padding_, stride_, filterSize_, imgSize_, imgSizeY_;
101+
int paddingY_, strideY_, filterSizeY_;
102+
int imgPixels_, filterPixels_, filterChannels_, outputX_, outputY_, outputs_;
103+
104+
/// Following member variables are same with CudnnConvLayer.
105+
/// There is no explanation here.
106+
int fwdAlgo_, bwdFilterAlgo_, bwdDataAlgo_;
107+
size_t fwdLimitBytes_, bwdDataLimitBytes_, bwdFilterLimitBytes_;
108+
size_t workSpaceInBytes_;
109+
void *workSpace_;
110+
bool isSelectAlgo_;
111+
};
112+
113+
} // namespace paddle

paddle/gserver/layers/ConvBaseProjection.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,45 +93,48 @@ void ConvBaseProjection::initCudnn() {
9393
}
9494

9595
void ConvBaseProjection::reshapeTensorDesc(int batchSize) {
96+
// The stride between two consecutive samples in the output of ConvProjection
97+
// may not be numFilters_ * outputH_ * outputW_ (conv) or
98+
// channels_ * imageH_ * imageW_ (deconv)
99+
// for example, in the case of layer ConcatenateLayer2 with two
100+
// ConvProjection, the stride is the output_size of layer ConcatenateLayer2.
101+
// So the calculation of nStride is different from CudnnConvLayer.
102+
size_t nStrideImage, nStrideOutput;
103+
if (isDeconv_) {
104+
nStrideImage = out_->value->getStride();
105+
nStrideOutput = numFilters_ * outputH_ * outputW_;
106+
} else {
107+
nStrideImage = channels_ * imageH_ * imageW_;
108+
nStrideOutput = out_->value->getStride();
109+
}
110+
96111
hl_tensor_reshape(imageDesc_,
97112
batchSize,
98113
channels_ / groups_,
99114
imageH_,
100115
imageW_,
101-
channels_ * imageH_ * imageW_,
116+
nStrideImage,
102117
imageH_ * imageW_,
103118
imageW_,
104119
1);
105-
hl_reset_convolution_descriptor(convDesc_,
106-
imageDesc_,
107-
filterDesc_,
108-
paddingH_,
109-
paddingW_,
110-
strideH_,
111-
strideW_);
112-
113-
// The stride between two consecutive images in ConvProjection may not be 1,
114-
// for example, in the case of layer ConcatenateLayer2 with two
115-
// ConvProjection, the stride is the output_size of layer ConcatenateLayer2.
116-
// So the calculation of nStride is different from CudnnConvLayer.
117-
// In fact, only "nStride = out_->value->getStride()" is ok.
118-
// size_t nStride = numFilters_ * outputH_ * outputW_;
119-
// if (out_->value->isContiguous()) {
120-
// CHECK_EQ(nStride, out_->value->getWidth());
121-
// } else {
122-
// nStride = out_->value->getStride();
123-
// }
124-
size_t nStride = out_->value->getStride();
125120

126121
hl_tensor_reshape(outputDesc_,
127122
batchSize,
128123
numFilters_ / groups_,
129124
outputH_,
130125
outputW_,
131-
nStride,
126+
nStrideOutput,
132127
outputH_ * outputW_,
133128
outputW_,
134129
1);
130+
131+
hl_reset_convolution_descriptor(convDesc_,
132+
imageDesc_,
133+
filterDesc_,
134+
paddingH_,
135+
paddingW_,
136+
strideH_,
137+
strideW_);
135138
}
136139

137140
void ConvBaseProjection::reshape(int batchSize) {

0 commit comments

Comments
 (0)