1# NCNN增加自定义层 2 3## 举例 4 5这里举个例子添加自定义层次 如Relu6,即 std::min(6, std::max(0, val)) 6 7``` 8Input input 0 1 input 9Convolution conv2d 1 1 input conv2d 0=32 1=1 2=1 3=1 4=0 5=0 6=768 10Relu6 relu6 1 1 conv2d relu6 11Pooling maxpool 1 1 relu6 maxpool 0=0 1=3 2=2 3=-233 4=0 12``` 13 14 15 16## 定义源码h文件:src/layer/relu6.h 17 18```CPP 19#ifndef LAYER_RELU6_H 20#define LAYER_RELU6_H 21 22#include "layer.h" 23 24namespace ncnn { 25 26class Relu6 : public Layer 27{ 28public: 29 Relu6(); 30 31 virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; 32}; 33 34} // namespace ncnn 35 36#endif // LAYER_RELU6_H 37``` 38 39 40 41## 定义源码CPP文件:src/layer/relu6.cpp 42 43```CPP 44#include "relu6.h" 45 46#include <math.h> 47 48namespace ncnn { 49 50Relu6::Relu6() 51{ 52 one_blob_only = true; 53 support_inplace = true; 54} 55 56int Relu6::forward_inplace(Mat& bottom_top_blob, const Option& opt) const 57{ 58 int w = bottom_top_blob.w; 59 int h = bottom_top_blob.h; 60 int channels = bottom_top_blob.c; 61 int size = w * h; 62 63 #pragma omp parallel for num_threads(opt.num_threads) 64 for (int q=0; q < channels; q++) 65 { 66 float* ptr = bottom_top_blob.channel(q); 67 68 for (int i=0; i<size; i++) 69 { 70 ptr[i] = std::min(6, std::max(0, ptr[i])); 71 } 72 } 73 74 return 0; 75} 76 77} // namespace ncnn 78 79``` 80 81 82 83## 修改 src/CMakeLists.txt 注册Relu6 84 85```CPP 86ncnn_add_layer(GroupNorm) 87ncnn_add_layer(LayerNorm) 88ncnn_add_layer(Relu6) 89``` 90 91 92 93## 定义测试用例CPP文件 src/test_relu6.cpp 94 95```CPP 96#include "layer/relu6.h" 97#include "testutil.h" 98 99static int test_relu6(const ncnn::Mat& a) 100{ 101 ncnn::ParamDict pd; 102 103 std::vector<ncnn::Mat> weights(0); 104 105 int ret = test_layer<ncnn::Relu6>("Relu6", pd, weights, a); 106 if (ret != 0) 107 { 108 fprintf(stderr, "test_relu6 failed a.dims=%d a=(%d %d %d)\n", a.dims, a.w, a.h, a.c); 109 } 110 111 return ret; 112} 113 114static int test_relu6_0() 115{ 116 return 0 117 || test_relu6(RandomMat(5, 7, 24)) 118 || test_relu6(RandomMat(7, 9, 12)) 119 || test_relu6(RandomMat(3, 5, 13)); 120} 121 122static int test_relu6_1() 123{ 124 return 0 125 || test_relu6(RandomMat(15, 24)) 126 || test_relu6(RandomMat(17, 12)) 127 || test_relu6(RandomMat(19, 15)); 128} 129 130static int test_relu6_2() 131{ 132 return 0 133 || test_relu6(RandomMat(128)) 134 || test_relu6(RandomMat(124)) 135 || test_relu6(RandomMat(127)); 136} 137 138int main() 139{ 140 SRAND(7767517); 141 142 return 0 143 || test_relu6_0() 144 || test_relu6_1() 145 || test_relu6_2(); 146} 147 148``` 149 150 151 152## 修改tests/CMakeLists.txt 注册Relu6测试用例 153 154```CPP 155ncnn_add_layer_test(LSTM) 156ncnn_add_layer_test(Yolov3DetectionOutput) 157ncnn_add_layer_test(Relu6) 158``` 159 160 161 162## 编译 163 164``` 165按原NCNN步骤编译 166``` 167 168 169 170## 单元测试 171 172``` 173./test_relu6 174``` 175 176