|
| 1 | +#include <vector> |
| 2 | + |
| 3 | +#include "caffe/layers/broadcast_to_layer.hpp" |
| 4 | +#include "caffe/util/math_functions.hpp" |
| 5 | + |
| 6 | +namespace caffe { |
| 7 | + |
| 8 | +template <typename Dtype> |
| 9 | +void BroadcastToLayer<Dtype>::LayerSetUp( |
| 10 | + const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { |
| 11 | + const BroadcastToParameter& broadcast_to_param = this->layer_param_.broadcast_to_param(); |
| 12 | + output_shape_.clear(); |
| 13 | + std::copy(broadcast_to_param.shape().begin(), |
| 14 | + broadcast_to_param.shape().end(), |
| 15 | + std::back_inserter(output_shape_)); |
| 16 | + |
| 17 | + CHECK_GE(output_shape_.size(), bottom[0]->num_axes()) << "Output shape should not have less axis than input!"; |
| 18 | + int dim_diff = output_shape_.size() - bottom[0]->num_axes(); |
| 19 | + for(int i=output_shape_.size()-1; i>=dim_diff; i--) |
| 20 | + { |
| 21 | + CHECK_GT(output_shape_[i], 0) << "Values in output shape must be positive!"; |
| 22 | + CHECK(output_shape_[i]==bottom[0]->shape(i-dim_diff) || bottom[0]->shape(i-dim_diff)==1) |
| 23 | + << "The broadcasting shape is incompatible with the input!"; |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | + |
| 28 | +template <typename Dtype> |
| 29 | +void BroadcastToLayer<Dtype>::Reshape( |
| 30 | + const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { |
| 31 | + top[0]->Reshape(output_shape_); |
| 32 | +} |
| 33 | + |
| 34 | +template <typename Dtype> |
| 35 | +void BroadcastToLayer<Dtype>::Forward_cpu( |
| 36 | + const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { |
| 37 | + const Dtype* bottom_data = bottom[0]->cpu_data(); |
| 38 | + Dtype* top_data = top[0]->mutable_cpu_data(); |
| 39 | + int count = top[0]->count(); |
| 40 | + |
| 41 | + int dim = top[0]->num_axes(); |
| 42 | + int dim_diff = output_shape_.size() - bottom[0]->num_axes(); |
| 43 | + // Assume top index (x,y,z) with top shape (A, B, C) |
| 44 | + // top offset d = xBC + yC + z |
| 45 | + // So to count the bottom index, should first figure out x, y, z |
| 46 | + // x = d / BC |
| 47 | + // y = (d % BC) / C |
| 48 | + // z = d % C |
| 49 | + // Then consider bottom shape (A', B', C'), where A' = 1 or A |
| 50 | + // So bottom offset = x'B'C' + y'C' + z |
| 51 | + for(int d=0; d<count; d++) |
| 52 | + { |
| 53 | + int offset = 0; |
| 54 | + |
| 55 | + for(int i=dim_diff;i<dim-1;i++) |
| 56 | + { |
| 57 | + int num = (d % top[0]->count(i)) / top[0]->count(i+1); |
| 58 | + int n0 = 1 == bottom[0]->shape(i-dim_diff) ? 0 : num; |
| 59 | + offset += n0 * bottom[0]->count(i-dim_diff+1); |
| 60 | + } |
| 61 | + int z = d % top[0]->shape(dim-1); |
| 62 | + int z0 = 1 == bottom[0]->shape(dim-dim_diff-1) ? 0 : z; |
| 63 | + offset += z0; |
| 64 | + |
| 65 | + top_data[d] = bottom_data[offset]; |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +template <typename Dtype> |
| 70 | +void BroadcastToLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, |
| 71 | + const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { |
| 72 | + NOT_IMPLEMENTED; |
| 73 | +} |
| 74 | + |
| 75 | +//#ifdef CPU_ONLY |
| 76 | +//STUB_GPU(TileLayer); |
| 77 | +//#endif |
| 78 | + |
| 79 | +INSTANTIATE_CLASS(BroadcastToLayer); |
| 80 | +REGISTER_LAYER_CLASS(BroadcastTo); |
| 81 | + |
| 82 | +} // namespace caffe |
0 commit comments