forked from kevinlin311tw/Caffe-DeepBinaryCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilter_layer.cpp
More file actions
127 lines (116 loc) · 4.59 KB
/
filter_layer.cpp
File metadata and controls
127 lines (116 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <algorithm>
#include <vector>
#include "caffe/layer.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/vision_layers.hpp"
namespace caffe {
template <typename Dtype>
void FilterLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
CHECK_EQ(top.size(), bottom.size() - 1);
first_reshape_ = true;
}
template <typename Dtype>
void FilterLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
// bottom[0...k-1] are the blobs to filter
// bottom[last] is the "selector_blob"
int selector_index = bottom.size() - 1;
for (int i = 1; i < bottom[selector_index]->num_axes(); ++i) {
CHECK_EQ(bottom[selector_index]->shape(i), 1)
<< "Selector blob dimensions must be singletons (1), except the first";
}
for (int i = 0; i < bottom.size() - 1; ++i) {
CHECK_EQ(bottom[selector_index]->shape(0), bottom[i]->shape(0)) <<
"Each bottom should have the same 0th dimension as the selector blob";
}
const Dtype* bottom_data_selector = bottom[selector_index]->cpu_data();
indices_to_forward_.clear();
// look for non-zero elements in bottom[0]. Items of each bottom that
// have the same index as the items in bottom[0] with value == non-zero
// will be forwarded
for (int item_id = 0; item_id < bottom[selector_index]->shape(0); ++item_id) {
// we don't need an offset because item size == 1
const Dtype* tmp_data_selector = bottom_data_selector + item_id;
if (*tmp_data_selector) {
indices_to_forward_.push_back(item_id);
}
}
// only filtered items will be forwarded
int new_tops_num = indices_to_forward_.size();
// init
if (first_reshape_) {
new_tops_num = bottom[0]->shape(0);
first_reshape_ = false;
}
for (int t = 0; t < top.size(); ++t) {
int num_axes = bottom[t]->num_axes();
vector<int> shape_top(num_axes);
shape_top[0] = new_tops_num;
for (int ts = 1; ts < num_axes; ++ts)
shape_top[ts] = bottom[t]->shape(ts);
top[t]->Reshape(shape_top);
}
}
template <typename Dtype>
void FilterLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
int new_tops_num = indices_to_forward_.size();
// forward all filtered items for all bottoms but the Selector (bottom[last])
for (int t = 0; t < top.size(); ++t) {
const Dtype* bottom_data = bottom[t]->cpu_data();
Dtype* top_data = top[t]->mutable_cpu_data();
int dim = bottom[t]->count() / bottom[t]->shape(0);
for (int n = 0; n < new_tops_num; ++n) {
int data_offset_top = n * dim;
int data_offset_bottom = indices_to_forward_[n] * bottom[t]->count(1);
caffe_copy(dim, bottom_data + data_offset_bottom,
top_data + data_offset_top);
}
}
}
template <typename Dtype>
void FilterLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
if (propagate_down[bottom.size() - 1]) {
LOG(FATAL) << this->type()
<< "Layer cannot backpropagate to filter index inputs";
}
for (int i = 0; i < top.size(); i++) {
// bottom[last] is the selector and never needs backpropagation
// so we can iterate over top vector because top.size() == bottom.size() -1
if (propagate_down[i]) {
const int dim = top[i]->count() / top[i]->shape(0);
int next_to_backward_offset = 0;
int batch_offset = 0;
int data_offset_bottom = 0;
int data_offset_top = 0;
for (int n = 0; n < bottom[i]->shape(0); n++) {
data_offset_bottom = n * dim;
if (next_to_backward_offset >= indices_to_forward_.size()) {
// we already visited all items that were been forwarded, so
// just set to zero remaining ones
caffe_set(dim, Dtype(0),
bottom[i]->mutable_cpu_diff() + data_offset_bottom);
} else {
batch_offset = indices_to_forward_[next_to_backward_offset];
if (n != batch_offset) { // this data was not been forwarded
caffe_set(dim, Dtype(0),
bottom[i]->mutable_cpu_diff() + data_offset_bottom);
} else { // this data was been forwarded
data_offset_top = next_to_backward_offset * dim;
next_to_backward_offset++; // point to next forwarded item index
caffe_copy(dim, top[i]->mutable_cpu_diff() + data_offset_top,
bottom[i]->mutable_cpu_diff() + data_offset_bottom);
}
}
}
}
}
}
#ifdef CPU_ONLY
STUB_GPU(FilterLayer);
#endif
INSTANTIATE_CLASS(FilterLayer);
REGISTER_LAYER_CLASS(Filter);
} // namespace caffe