Skip to content

Commit 7c71b6d

Browse files
committed
add the TileND layer for multiple dimension tile
1 parent 112b2ec commit 7c71b6d

File tree

3 files changed

+216
-3
lines changed

3 files changed

+216
-3
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef CAFFE_TILE_ND_LAYER_HPP_
2+
#define CAFFE_TILE_ND_LAYER_HPP_
3+
4+
#include <vector>
5+
6+
#include "caffe/blob.hpp"
7+
#include "caffe/layer.hpp"
8+
#include "caffe/proto/caffe.pb.h"
9+
10+
namespace caffe {
11+
12+
/**
13+
* @brief Copy a Blob along specified dimensions.
14+
*/
15+
template <typename Dtype>
16+
class TileNDLayer : public Layer<Dtype> {
17+
public:
18+
explicit TileNDLayer(const LayerParameter& param)
19+
: Layer<Dtype>(param) {}
20+
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
21+
const vector<Blob<Dtype>*>& top);
22+
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
23+
const vector<Blob<Dtype>*>& top);
24+
25+
virtual inline const char* type() const { return "TileND"; }
26+
virtual inline int ExactNumBottomBlobs() const { return 1; }
27+
virtual inline int ExactNumTopBlobs() const { return 1; }
28+
29+
protected:
30+
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
31+
const vector<Blob<Dtype>*>& top);
32+
//virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
33+
// const vector<Blob<Dtype>*>& top);
34+
35+
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
36+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
37+
//virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
38+
// const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
39+
40+
vector<int> axis_;
41+
vector<int> tiles_;
42+
vector<int> outer_dim_, inner_dim_;
43+
vector<int> top_inner_dim_;
44+
Blob<Dtype> top_temp_;
45+
};
46+
47+
} // namespace caffe
48+
49+
#endif // CAFFE_TILE_ND_LAYER_HPP_

src/caffe/layers/tile_nd_layer.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#include <vector>
2+
3+
#include "caffe/layers/tile_nd_layer.hpp"
4+
#include "caffe/util/math_functions.hpp"
5+
6+
namespace caffe {
7+
8+
template <typename Dtype>
9+
void TileNDLayer<Dtype>::LayerSetUp(
10+
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
11+
const TileNDParameter& tile_nd_param = this->layer_param_.tile_nd_param();
12+
axis_.clear();
13+
std::copy(tile_nd_param.axis().begin(),
14+
tile_nd_param.axis().end(),
15+
std::back_inserter(axis_));
16+
tiles_.clear();
17+
std::copy(tile_nd_param.tiles().begin(),
18+
tile_nd_param.tiles().end(),
19+
std::back_inserter(tiles_));
20+
21+
CHECK_EQ(axis_.size(), tiles_.size()) << "Number of tiles must be equal to axis!";
22+
CHECK_GT(tiles_.size(), 0) << "Number of tiles must be positive!";
23+
for(int i=0;i<axis_.size();i++)
24+
{
25+
axis_[i] = bottom[0]->CanonicalAxisIndex(axis_[i]);
26+
CHECK_GT(tiles_[i], 0) << "Value of tiles must be positive!";
27+
}
28+
}
29+
30+
31+
template <typename Dtype>
32+
void TileNDLayer<Dtype>::Reshape(
33+
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
34+
vector<int> top_shape = bottom[0]->shape();
35+
for(int i=axis_.size()-1;i>=0;i--)
36+
top_shape[axis_[i]] = bottom[0]->shape(axis_[i]) * tiles_[i];
37+
38+
top[0]->Reshape(top_shape);
39+
top_temp_.Reshape(top_shape);
40+
41+
outer_dim_.clear();
42+
inner_dim_.clear();
43+
44+
int multiple = 1;
45+
for(int i=axis_.size()-1; i>=0; i--) //notice the order
46+
{
47+
outer_dim_.push_back(bottom[0]->count(0, axis_[i]));
48+
inner_dim_.push_back(bottom[0]->count(axis_[i]));
49+
top_inner_dim_.push_back(bottom[0]->count(axis_[i])*multiple);
50+
multiple *= tiles_[i];
51+
}
52+
53+
// reverse the order to make it align with the tiles and handling (from right to left dimension)
54+
vector<int> tmp(outer_dim_);
55+
outer_dim_.clear();
56+
std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(outer_dim_));
57+
tmp = inner_dim_;
58+
inner_dim_.clear();
59+
std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(inner_dim_));
60+
tmp = top_inner_dim_;
61+
top_inner_dim_.clear();
62+
std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(top_inner_dim_));
63+
64+
//for(int i=0;i<axis_.size();i++)
65+
// LOG(INFO)<<"out: "<<outer_dim_[i]<<", in: "<<inner_dim_[i]<<", top: "<<top_inner_dim_[i]<<"\n";
66+
}
67+
68+
template <typename Dtype>
69+
void TileNDLayer<Dtype>::Forward_cpu(
70+
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
71+
const Dtype* bottom_data = bottom[0]->cpu_data();
72+
//Dtype* top_data = top[0]->mutable_cpu_data();
73+
int s = outer_dim_.size()-1; //copy from most right dimension
74+
Dtype* top_data_temp = top_temp_.mutable_cpu_data();
75+
for (int i = 0; i < outer_dim_[s]; ++i) {
76+
for (int t = 0; t < tiles_[s]; ++t) {
77+
caffe_copy(inner_dim_[s], bottom_data, top_data_temp);
78+
top_data_temp += inner_dim_[s];
79+
}
80+
bottom_data += inner_dim_[s];
81+
}
82+
83+
//top_data_temp = top_temp_.mutable_cpu_data();
84+
//for (int i = 0; i < top_temp_.count(); ++i)
85+
// LOG(INFO)<<top_data_temp[i]<<"\n";
86+
//LOG(INFO)<<"stage2\n";
87+
88+
for(int s=outer_dim_.size()-2;s>0;s--)
89+
{
90+
Dtype* input_data = top_temp_.mutable_cpu_data();
91+
Dtype* output_data = top[0]->mutable_cpu_data();
92+
for (int i = 0; i < outer_dim_[s]; ++i) {
93+
for (int t = 0; t < tiles_[s]; ++t) {
94+
caffe_copy(top_inner_dim_[s], input_data, output_data);
95+
output_data += top_inner_dim_[s];
96+
}
97+
input_data += top_inner_dim_[s];
98+
}
99+
100+
//top_data_temp = top[0]->mutable_cpu_data();
101+
//for (int i = 0; i < top[0]->count(); ++i)
102+
// LOG(INFO)<<top_data_temp[i]<<"\n";
103+
//LOG(INFO)<<"stage3\n";
104+
105+
Dtype* next_input_data = top[0]->mutable_cpu_data();
106+
Dtype* copy_data = top_temp_.mutable_cpu_data();
107+
caffe_copy(top[0]->count(axis_[s-1]), next_input_data, copy_data); //reset for the next loop
108+
109+
//top_data_temp = top_temp_.mutable_cpu_data();
110+
//for (int i = 0; i < top_temp_.count(); ++i)
111+
// LOG(INFO)<<top_data_temp[i]<<"\n";
112+
//LOG(INFO)<<"stage4\n";
113+
}
114+
115+
// final(first) dimension to tile
116+
s = 0;
117+
Dtype* input_data = top_temp_.mutable_cpu_data();
118+
Dtype* output_data = top[0]->mutable_cpu_data();
119+
for (int i = 0; i < outer_dim_[s]; ++i) {
120+
for (int t = 0; t < tiles_[s]; ++t) {
121+
caffe_copy(top_inner_dim_[s], input_data, output_data);
122+
output_data += top_inner_dim_[s];
123+
}
124+
input_data += top_inner_dim_[s];
125+
}
126+
}
127+
128+
template <typename Dtype>
129+
void TileNDLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
130+
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
131+
if (!propagate_down[0]) { return; }
132+
const Dtype* top_diff = top[0]->cpu_diff();
133+
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
134+
for(int s=outer_dim_.size()-1;s>=0;s--)
135+
{
136+
for (int i = 0; i < outer_dim_[s]; ++i) {
137+
caffe_copy(inner_dim_[s], top_diff, bottom_diff);
138+
top_diff += inner_dim_[s];
139+
for (int t = 1; t < tiles_[s]; ++t) {
140+
caffe_axpy(inner_dim_[s], Dtype(1), top_diff, bottom_diff);
141+
top_diff += inner_dim_[s];
142+
}
143+
bottom_diff += inner_dim_[s];
144+
}
145+
}
146+
}
147+
148+
//#ifdef CPU_ONLY
149+
//STUB_GPU(TileLayer);
150+
//#endif
151+
152+
INSTANTIATE_CLASS(TileNDLayer);
153+
REGISTER_LAYER_CLASS(TileND);
154+
155+
} // namespace caffe

src/caffe/proto/caffe.proto

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ message ParamSpec {
460460
// NOTE
461461
// Update the next available ID when you add a new LayerParameter field.
462462
//
463-
// LayerParameter next available layer-specific ID: 238 (last added: mirror_pad_param)
463+
// LayerParameter next available layer-specific ID: 240 (last added: tile_nd_param)
464464
message LayerParameter {
465465
optional string name = 1; // the layer name
466466
optional string type = 2; // the layer type
@@ -642,6 +642,7 @@ message LayerParameter {
642642
optional BatchToSpaceNDParameter batch_to_space_nd_param = 235;
643643
optional SpaceToBatchNDParameter space_to_batch_nd_param = 236;
644644
optional MirrorPadParameter mirror_pad_param = 238;
645+
optional TileNDParameter tile_nd_param = 239;
645646
}
646647

647648
message AccumParameter {
@@ -3037,8 +3038,8 @@ message SeLuDropoutParameter {
30373038
}
30383039

30393040
message UnstackParameter {
3040-
optional uint32 num = 1[default = 0];
3041-
optional int32 axis = 2[default = 0];
3041+
optional uint32 num = 1[default = 0];
3042+
optional int32 axis = 2[default = 0];
30423043
}
30433044

30443045
message SpaceToBatchNDParameter{
@@ -3050,3 +3051,11 @@ message BatchToSpaceNDParameter{
30503051
repeated uint32 block_shape = 1;
30513052
repeated uint32 crops = 2;
30523053
}
3054+
3055+
// Message that stores parameters used by TileNDLayer
3056+
message TileNDParameter {
3057+
// The index of the axis to tile.
3058+
repeated int32 axis = 1;
3059+
// The number of copies (tiles) of the blob to output.
3060+
repeated uint32 tiles = 2;
3061+
}

0 commit comments

Comments
 (0)