|
|
@@ -157,6 +157,60 @@ class XavierFiller : public Filler<Dtype> { |
|
|
};
|
|
|
|
|
|
|
|
|
+/*!
|
|
|
+@brief Fills a Blob with coefficients of bilinear interpolation for upsampling.
|
|
|
+
|
|
|
+This is intended to be used in DeconvolutionLayer acting as UpsamplingLayer.
|
|
|
+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_upsampling" } 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 <typename Dtype>
|
|
|
+class BilinearUpsamplingFiller : public Filler<Dtype> {
|
|
|
+ public:
|
|
|
+ explicit BilinearUpsamplingFiller(const FillerParameter& param)
|
|
|
+ : Filler<Dtype>(param) {}
|
|
|
+ virtual void Fill(Blob<Dtype>* 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.
|
|
|
*
|
|
|
@@ -176,6 +230,8 @@ Filler<Dtype>* GetFiller(const FillerParameter& param) { |
|
|
return new UniformFiller<Dtype>(param);
|
|
|
} else if (type == "xavier") {
|
|
|
return new XavierFiller<Dtype>(param);
|
|
|
+ } else if (type == "bilinear_upsampling") {
|
|
|
+ return new BilinearUpsamplingFiller<Dtype>(param);
|
|
|
} else {
|
|
|
CHECK(false) << "Unknown filler name: " << param.type();
|
|
|
}
|
|
|
|