├── README.md ├── shuffle_channel_layer.cpp ├── shuffle_channel_layer.cu └── shuffle_channel_layer.hpp /README.md: -------------------------------------------------------------------------------- 1 | # Caffe-ShuffleNet 2 | This is Re-implementation of ShuffleNet, For details, please read the original paper: 3 | ["ShuffleNet: An Extremely Efficient Convolutional 4 | Neural Network for Mobile Devices" by Xiangyu Zhang et. al. 2017](https://arxiv.org/pdf/1707.01083.pdf). If you find any bug, please drop me an email. Thanks. 5 | 6 | # Notes 7 | 8 | | group 1 | group 2 | group 3 | 9 | | :------: | :------: | :-------: | 10 | | 1 2 | 3 4 | 5 6 | 11 | 12 | Each nubmer represents a channel of the feature map 13 | 14 | ## step 1: Reshape 15 | 1 2 16 | 3 4 17 | 5 6 18 | ## step 2: transpose 19 | 1 3 5 20 | 2 4 6   21 | ## step 3: flatten 22 | 23 | | group 1 | group 2 | group 3 | 24 | | :-----: | :------: | :-------: | 25 | | 1 3 | 5 2 | 4 6 | 26 | 27 | # Acknowledgement   28 | [HolmesShuan](https://github.com/HolmesShuan) 29 | -------------------------------------------------------------------------------- /shuffle_channel_layer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "caffe/layers/shuffle_channel_layer.hpp" 5 | 6 | namespace caffe { 7 | 8 | template 9 | void ShuffleChannelLayer::LayerSetUp(const vector *> &bottom, const vector *> &top) 10 | { 11 | group_ = this->layer_param_.shuffle_channel_param().group(); 12 | CHECK_GT(group_, 0) << "group must be greater than 0"; 13 | temp_blob_.ReshapeLike(*bottom[0]); 14 | top[0]->ReshapeLike(*bottom[0]); 15 | } 16 | 17 | template 18 | void ShuffleChannelLayer::Resize_cpu(Dtype *output, const Dtype *input, int group_row, int group_column, int len) 19 | { 20 | for (int i = 0; i < group_row; ++i) // 2 21 | { 22 | for(int j = 0; j < group_column ; ++j) // 3 23 | { 24 | const Dtype* p_i = input + (i * group_column + j ) * len; 25 | Dtype* p_o = output + (j * group_row + i ) * len; 26 | 27 | caffe_copy(len, p_i, p_o); 28 | } 29 | } 30 | } 31 | 32 | template 33 | void ShuffleChannelLayer::Forward_cpu(const vector*>& bottom, 34 | const vector*>& top) { 35 | const Dtype* bottom_data = bottom[0]->cpu_data(); 36 | Dtype* top_data = top[0]->mutable_cpu_data(); 37 | 38 | const int num = bottom[0]->shape(0); 39 | const int feature_map_size = bottom[0]->count(1); 40 | const int sp_sz = bottom[0]->count(2); 41 | const int chs = bottom[0]->shape(1); 42 | 43 | int group_row = group_; 44 | int group_column = int(chs / group_row); 45 | CHECK_EQ(chs, (group_column * group_row)) << "Wrong group size."; 46 | 47 | Dtype* temp_data = temp_blob_.mutable_cpu_data(); 48 | for(int n = 0; n < num; ++n) 49 | { 50 | Resize_cpu(temp_data+n*feature_map_size, bottom_data +n*feature_map_size, group_row, group_column, sp_sz); 51 | } 52 | caffe_copy(bottom[0]->count(), temp_blob_.cpu_data(), top_data); 53 | } 54 | 55 | template 56 | void ShuffleChannelLayer::Backward_cpu(const vector*>& top, 57 | const vector& propagate_down, 58 | const vector*>& bottom) { 59 | if (propagate_down[0]) { 60 | const Dtype* top_diff = top[0]->cpu_diff(); 61 | Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); 62 | 63 | const int num = bottom[0]->shape(0); 64 | const int feature_map_size = bottom[0]->count(1); 65 | const int sp_sz = bottom[0]->count(2); 66 | const int chs = bottom[0]->shape(1); 67 | 68 | int group_row = int(chs / group_); 69 | int group_column = group_; 70 | 71 | Dtype* temp_diff = temp_blob_.mutable_cpu_diff(); 72 | for(int n = 0; n < num; ++n) 73 | { 74 | Resize_cpu(temp_diff + n * feature_map_size, top_diff+n*feature_map_size, group_row, group_column, sp_sz); 75 | } 76 | caffe_copy(top[0]->count(), temp_blob_.cpu_diff(), bottom_diff); 77 | } 78 | } 79 | 80 | 81 | #ifdef CPU_ONLY 82 | STUB_GPU(ShuffleChannelLayer); 83 | #endif 84 | 85 | INSTANTIATE_CLASS(ShuffleChannelLayer); 86 | REGISTER_LAYER_CLASS(ShuffleChannel); 87 | } // namespace caffe 88 | -------------------------------------------------------------------------------- /shuffle_channel_layer.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "caffe/layers/shuffle_channel_layer.hpp" 5 | 6 | namespace caffe { 7 | 8 | template 9 | void ShuffleChannelLayer::Resize_gpu(Dtype *output, const Dtype *input, int group_row, int group_column, int len) 10 | { 11 | for (int i = 0; i < group_row; ++i) // 2 12 | { 13 | for(int j = 0; j < group_column ; ++j) // 3 14 | { 15 | const Dtype* p_i = input + (i * group_column + j ) * len; 16 | Dtype* p_o = output + (j * group_row + i ) * len; 17 | 18 | caffe_copy(len, p_i, p_o); 19 | } 20 | } 21 | } 22 | 23 | template 24 | void ShuffleChannelLayer::Forward_gpu(const vector*>& bottom, 25 | const vector*>& top) { 26 | const Dtype* bottom_data = bottom[0]->gpu_data(); 27 | Dtype* top_data = top[0]->mutable_gpu_data(); 28 | 29 | const int num = bottom[0]->num(); 30 | const int feature_map_size = bottom[0]->count(1); 31 | const int sp_sz = bottom[0]->count(2); 32 | const int chs = bottom[0]->channels(); 33 | 34 | int group_row = group_; 35 | int group_column = int(chs / group_row); 36 | CHECK_EQ(chs, (group_column * group_row)) << "Wrong group size."; 37 | 38 | Dtype* temp_data = temp_blob_.mutable_gpu_data(); 39 | for(int n = 0; n < num; ++n) 40 | { 41 | Resize_gpu(temp_data+n*feature_map_size, bottom_data +n*feature_map_size, group_row, group_column, sp_sz); 42 | } 43 | caffe_copy(bottom[0]->count(), temp_blob_.gpu_data(), top_data); 44 | } 45 | 46 | template 47 | void ShuffleChannelLayer::Backward_gpu(const vector*>& top, 48 | const vector& propagate_down, 49 | const vector*>& bottom) { 50 | if (propagate_down[0]) { 51 | const Dtype* top_diff = top[0]->gpu_diff(); 52 | Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); 53 | 54 | const int num = bottom[0]->num(); 55 | const int feature_map_size = bottom[0]->count(1); 56 | const int sp_sz = bottom[0]->count(2); 57 | const int chs = bottom[0]->channels(); 58 | 59 | int group_row = int(chs / group_); 60 | int group_column = group_; 61 | 62 | Dtype* temp_diff = temp_blob_.mutable_gpu_diff(); 63 | for(int n = 0; n < num; ++n) 64 | { 65 | Resize_gpu(temp_diff + n * feature_map_size, top_diff+n*feature_map_size, group_row, group_column, sp_sz); 66 | } 67 | caffe_copy(top[0]->count(), temp_blob_.gpu_diff(), bottom_diff); 68 | } 69 | } 70 | 71 | INSTANTIATE_LAYER_GPU_FUNCS(ShuffleChannelLayer); 72 | 73 | } // namespace caffe 74 | -------------------------------------------------------------------------------- /shuffle_channel_layer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CAFFE_SHUFFLE_CHANNEL_LAYER_HPP_ 2 | #define CAFFE_SHUFFLE_CHANNEL_LAYER_HPP_ 3 | 4 | #include 5 | 6 | #include "caffe/blob.hpp" 7 | #include "caffe/layer.hpp" 8 | #include "caffe/proto/caffe.pb.h" 9 | 10 | namespace caffe { 11 | 12 | template 13 | class ShuffleChannelLayer : public Layer { 14 | public: 15 | explicit ShuffleChannelLayer(const LayerParameter& param) 16 | : Layer(param) {} 17 | virtual void LayerSetUp(const vector*>& bottom, 18 | const vector*>& top); 19 | virtual void Reshape(const vector*>& bottom, 20 | const vector*>& top) {} 21 | virtual inline const char* type() const { return "ShuffleChannel"; } 22 | 23 | protected: 24 | virtual void Forward_cpu(const vector*>& bottom, 25 | const vector*>& top); 26 | virtual void Forward_gpu(const vector*>& bottom, 27 | const vector*>& top); 28 | 29 | virtual void Backward_cpu(const vector*>& top, 30 | const vector& propagate_down, const vector*>& bottom); 31 | virtual void Backward_gpu(const vector*>& top, 32 | const vector& propagate_down, const vector*>& bottom); 33 | 34 | private: 35 | void Resize_cpu(Dtype *output, const Dtype *input, int group_row, int group_column, int len); 36 | void Resize_gpu(Dtype *output, const Dtype *input, int group_row, int group_column, int len); 37 | 38 | Blob temp_blob_; 39 | int group_; 40 | }; 41 | 42 | } // namespace caffe 43 | 44 | #endif // CAFFE_SHUFFLE_CHANNEL_LAYER_HPP_ 45 | --------------------------------------------------------------------------------