Browse Source

Update add-custom-layer.zh.md (#2164)

tags/20201208
ncnnnnn GitHub 5 years ago
parent
commit
697767b062
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 124 additions and 57 deletions
  1. +124
    -57
      docs/developer-guide/add-custom-layer.zh.md

+ 124
- 57
docs/developer-guide/add-custom-layer.zh.md View File

@@ -1,4 +1,8 @@
这里举个例子添加 Relu6,即 std::min(6, std::max(0, val))
# NCNN增加自定义层

## 举例

这里举个例子添加自定义层次 如Relu6,即 std::min(6, std::max(0, val))

```
Input input 0 1 input
@@ -7,102 +11,165 @@ Relu6 relu6 1 1 conv2d relu6
Pooling maxpool 1 1 relu6 maxpool 0=0 1=3 2=2 3=-233 4=0
```

## method 1 -- 注册自定义层
```cpp


## 定义源码h文件:src/layer/relu6.h

```CPP
#ifndef LAYER_RELU6_H
#define LAYER_RELU6_H

#include "layer.h"

class Relu6 : public ncnn::Layer
namespace ncnn {

class Relu6 : public Layer
{
public:
Relu6()
{
one_blob_only = true;
support_inplace = true;
}
Relu6();

virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const;
};

} // namespace ncnn

#endif // LAYER_RELU6_H
```



## 定义源码CPP文件:src/layer/relu6.cpp

```CPP
#include "relu6.h"

#include <math.h>

namespace ncnn {

Relu6::Relu6()
{
one_blob_only = true;
support_inplace = true;
}

int Relu6::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
int w = bottom_top_blob.w;
int h = bottom_top_blob.h;
int channels = bottom_top_blob.c;
int size = w * h;

#pragma omp parallel for num_threads(opt.num_threads)
for (int q=0; q<channels; q++)
for (int q=0; q < channels; q++)
{
float* outptr = bottom_top_blob.channel(q);
float* ptr = bottom_top_blob.channel(q);

for (int i=0; i<size; i++)
{
outptr[i] = std::min(6, std::max(0, outptr[i]));
ptr[i] = std::min(6, std::max(0, ptr[i]));
}
}

return 0;
}
};
}

} // namespace ncnn

DEFINE_LAYER_CREATOR(Relu6)
```

```cpp
ncnn::Net net;
net.register_custom_layer("Relu6", Relu6_layer_creator);

net.load_param("model.param");
net.load_model("model.bin");

ncnn::Extractor ex = net.create_extractor();
## 修改 src/CMakeLists.txt 注册Relu6

ex.input("input", inputmat);
ex.extract("maxpool", maxpoolmat);
```CPP
ncnn_add_layer(GroupNorm)
ncnn_add_layer(LayerNorm)
ncnn_add_layer(Relu6)
```


## method 2 -- 处理中间 blob
```cpp
ncnn::Net net;
net.load_param("model.param");
net.load_model("model.bin");

ncnn::Extractor ex = net.create_extractor();
## 定义测试用例CPP文件 src/test_relu6.cpp

ex.input("input", inputmat);
ex.extract("conv2d", conv2dmat);
```CPP
#include "layer/relu6.h"
#include "testutil.h"

// relu6
ncnn::Mat relu6mat = conv2dmat.clone();
static int test_relu6(const ncnn::Mat& a)
{
int w = relu6mat.w;
int h = relu6mat.h;
int channels = relu6mat.c;
int size = w * h;
ncnn::ParamDict pd;

std::vector<ncnn::Mat> weights(0);

#pragma omp parallel for
for (int q=0; q<channels; q++)
int ret = test_layer<ncnn::Relu6>("Relu6", pd, weights, a);
if (ret != 0)
{
float* outptr = relu6mat.channel(q);
for (int i=0; i<size; i++)
{
outptr[i] = std::min(6, std::max(0, outptr[i]));
}
fprintf(stderr, "test_relu6 failed a.dims=%d a=(%d %d %d)\n", a.dims, a.w, a.h, a.c);
}

return ret;
}

static int test_relu6_0()
{
return 0
|| test_relu6(RandomMat(5, 7, 24))
|| test_relu6(RandomMat(7, 9, 12))
|| test_relu6(RandomMat(3, 5, 13));
}

static int test_relu6_1()
{
return 0
|| test_relu6(RandomMat(15, 24))
|| test_relu6(RandomMat(17, 12))
|| test_relu6(RandomMat(19, 15));
}

static int test_relu6_2()
{
return 0
|| test_relu6(RandomMat(128))
|| test_relu6(RandomMat(124))
|| test_relu6(RandomMat(127));
}

int main()
{
SRAND(7767517);

return 0
|| test_relu6_0()
|| test_relu6_1()
|| test_relu6_2();
}

ex.input("relu6", relu6mat);
ex.extract("maxpool", maxpoolmat);
```



## 修改tests/CMakeLists.txt 注册Relu6测试用例

```CPP
ncnn_add_layer_test(LSTM)
ncnn_add_layer_test(Yolov3DetectionOutput)
ncnn_add_layer_test(Relu6)
```

## method 3 -- 直接修改 ncnn
实现 src/layer/relu6.h

实现 src/layer/relu6.cpp

修改 src/CMakeLists.txt
```cmake
ncnn_add_layer(UnaryOp)
ncnn_add_layer(ConvolutionDepthWise)
ncnn_add_layer(Padding)
ncnn_add_layer(Relu6)
## 编译

```
按原NCNN步骤编译
```



## 单元测试

```
./test_relu6
```


Loading…
Cancel
Save