From 41df4cdce942c22f0d89ad8b0990d3ee7bd9cf31 Mon Sep 17 00:00:00 2001 From: Takuya Narihira Date: Thu, 26 Mar 2015 19:04:15 -0700 Subject: [PATCH] bilinear filler -- useful for interpolation with DeconvolutionLayer This filler is a convenience for interpolating with DeconvolutionLayer or smoothing + downsampling with ConvolutionLayer for stride > 1. --- include/caffe/filler.hpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/include/caffe/filler.hpp b/include/caffe/filler.hpp index ff3542e..888f4a4 100644 --- a/include/caffe/filler.hpp +++ b/include/caffe/filler.hpp @@ -208,6 +208,60 @@ class MSRAFiller : public Filler { } }; +/*! +@brief Fills a Blob with coefficients for bilinear interpolation. + +A common use case is with the DeconvolutionLayer acting as upsampling. +You can upsample a feature map with shape of (B, C, H, W) by any integer factor +using the following proto. +\code +layer { + name: "upsample", type: "Deconvolution" + bottom: "{{bottom_name}}" top: "{{top_name}}" + convolution_param { + kernel_size: {{2 * factor - factor % 2}} stride: {{factor}} + num_output: {{C}} group: {{C}} + pad: {{ceil((factor - 1) / 2.)}} + weight_filler: { type: "bilinear" } bias_term: false + } + param { lr_mult: 0 decay_mult: 0 } +} +\endcode +Please use this by replacing `{{}}` with your values. By specifying +`num_output: {{C}} group: {{C}}`, it behaves as +channel-wise convolution. The filter shape of this deconvolution layer will be +(C, 1, K, K) where K is `kernel_size`, and this filler will set a (K, K) +interpolation kernel for every channel of the filter identically. The resulting +shape of the top feature map will be (B, C, factor * H, factor * W). +Note that the learning rate and the +weight decay are set to 0 in order to keep coefficient values of bilinear +interpolation unchanged during training. If you apply this to an image, this +operation is equivalent to the following call in Python with Scikit.Image. +\code{.py} +out = skimage.transform.rescale(img, factor, mode='constant', cval=0) +\endcode + */ +template +class BilinearFiller : public Filler { + public: + explicit BilinearFiller(const FillerParameter& param) + : Filler(param) {} + virtual void Fill(Blob* blob) { + CHECK_EQ(blob->num_axes(), 4) << "Blob must be 4 dim."; + CHECK_EQ(blob->width(), blob->height()) << "Filter must be square"; + Dtype* data = blob->mutable_cpu_data(); + int f = ceil(blob->width() / 2.); + float c = (2 * f - 1 - f % 2) / (2. * f); + for (int i = 0; i < blob->count(); ++i) { + float x = i % blob->width(); + float y = (i / blob->width()) % blob->height(); + data[i] = (1 - fabs(x / f - c)) * (1 - fabs(y / f - c)); + } + CHECK_EQ(this->filler_param_.sparse(), -1) + << "Sparsity not supported by this Filler."; + } +}; + /** * @brief Get a specific filler from the specification given in FillerParameter. * @@ -229,6 +283,8 @@ Filler* GetFiller(const FillerParameter& param) { return new XavierFiller(param); } else if (type == "msra") { return new MSRAFiller(param); + } else if (type == "bilinear") { + return new BilinearFiller(param); } else { CHECK(false) << "Unknown filler name: " << param.type(); } -- 2.7.4