virtual inline const char* type() const { return "SPP"; }
virtual inline int ExactNumBottomBlobs() const { return 1; }
- virtual inline int MinTopBlobs() const { return 1; }
- // MAX POOL layers can output an extra top blob for the mask;
- // others can only output the pooled inputs.
- virtual inline int MaxTopBlobs() const {
- return (this->layer_param_.pooling_param().pool() ==
- PoolingParameter_PoolMethod_MAX) ? 2 : 1;
- }
+ virtual inline int ExactNumTopBlobs() const { return 1; }
protected:
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
int pyramid_height_;
int bottom_h_, bottom_w_;
+ int num_;
int channels_;
int kernel_h_, kernel_w_;
int pad_h_, pad_w_;
+ bool reshaped_first_time_;
/// the internal Split layer that feeds the pooling layers
shared_ptr<SplitLayer<Dtype> > split_layer_;
const vector<Blob<Dtype>*>& top) {
SPPParameter spp_param = this->layer_param_.spp_param();
+ num_ = bottom[0]->num();
+ channels_ = bottom[0]->channels();
bottom_h_ = bottom[0]->height();
bottom_w_ = bottom[0]->width();
+ reshaped_first_time_ = false;
CHECK_GT(bottom_h_, 0) << "Input dimensions cannot be zero.";
CHECK_GT(bottom_w_, 0) << "Input dimensions cannot be zero.";
flatten_outputs_.clear();
concat_bottom_vec_.clear();
+ if (pyramid_height_ == 1) {
+ // pooling layer setup
+ LayerParameter pooling_param = GetPoolingParam(0, bottom_h_, bottom_w_,
+ spp_param);
+ pooling_layers_.push_back(shared_ptr<PoolingLayer<Dtype> > (
+ new PoolingLayer<Dtype>(pooling_param)));
+ pooling_layers_[0]->SetUp(bottom, top);
+ return;
+ }
// split layer output holders setup
for (int i = 0; i < pyramid_height_; i++) {
split_top_vec_.push_back(new Blob<Dtype>());
const vector<Blob<Dtype>*>& top) {
CHECK_EQ(4, bottom[0]->num_axes()) << "Input must have 4 axes, "
<< "corresponding to (num, channels, height, width)";
+ // Do nothing if bottom shape is unchanged since last Reshape
+ if (num_ == bottom[0]->num() && channels_ == bottom[0]->channels() &&
+ bottom_h_ == bottom[0]->height() && bottom_w_ == bottom[0]->width() &&
+ reshaped_first_time_) {
+ return;
+ }
+ num_ = bottom[0]->num();
channels_ = bottom[0]->channels();
bottom_h_ = bottom[0]->height();
bottom_w_ = bottom[0]->width();
+ reshaped_first_time_ = true;
SPPParameter spp_param = this->layer_param_.spp_param();
+ if (pyramid_height_ == 1) {
+ LayerParameter pooling_param = GetPoolingParam(0, bottom_h_, bottom_w_,
+ spp_param);
+ pooling_layers_[0].reset(new PoolingLayer<Dtype>(pooling_param));
+ pooling_layers_[0]->SetUp(bottom, top);
+ pooling_layers_[0]->Reshape(bottom, top);
+ return;
+ }
split_layer_->Reshape(bottom, split_top_vec_);
for (int i = 0; i < pyramid_height_; i++) {
LayerParameter pooling_param = GetPoolingParam(
template <typename Dtype>
void SPPLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
+ if (pyramid_height_ == 1) {
+ pooling_layers_[0]->Forward(bottom, top);
+ return;
+ }
split_layer_->Forward(bottom, split_top_vec_);
for (int i = 0; i < pyramid_height_; i++) {
pooling_layers_[i]->Forward(
if (!propagate_down[0]) {
return;
}
+ if (pyramid_height_ == 1) {
+ pooling_layers_[0]->Backward(top, propagate_down, bottom);
+ return;
+ }
vector<bool> concat_propagate_down(pyramid_height_, true);
concat_layer_->Backward(top, concat_propagate_down, concat_bottom_vec_);
for (int i = 0; i < pyramid_height_; i++) {