Browse Source

groupnorm layer

tags/20200916
nihuini 5 years ago
parent
commit
4ad5230c2a
6 changed files with 214 additions and 1 deletions
  1. +1
    -0
      src/CMakeLists.txt
  2. +108
    -0
      src/layer/groupnorm.cpp
  3. +46
    -0
      src/layer/groupnorm.h
  4. +1
    -1
      src/layer/instancenorm.cpp
  5. +1
    -0
      tests/CMakeLists.txt
  6. +57
    -0
      tests/test_groupnorm.cpp

+ 1
- 0
src/CMakeLists.txt View File

@@ -138,6 +138,7 @@ ncnn_add_layer(Mish)
ncnn_add_layer(StatisticsPooling)
ncnn_add_layer(Swish)
ncnn_add_layer(Gemm)
ncnn_add_layer(GroupNorm)

if(NCNN_VULKAN)
ncnn_add_shader(${CMAKE_CURRENT_SOURCE_DIR}/convert_ycbcr.comp)


+ 108
- 0
src/layer/groupnorm.cpp View File

@@ -0,0 +1,108 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "groupnorm.h"

#include <math.h>

namespace ncnn {

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

int GroupNorm::load_param(const ParamDict& pd)
{
group = pd.get(0, 1);
channels = pd.get(1, 0);
eps = pd.get(2, 0.001f);

return 0;
}

int GroupNorm::load_model(const ModelBin& mb)
{
gamma_data = mb.load(channels, 1);
if (gamma_data.empty())
return -100;

beta_data = mb.load(channels, 1);
if (beta_data.empty())
return -100;

return 0;
}

int GroupNorm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
// x = (x - mean) / sqrt(var + eps) * gamma + beta

int w = bottom_top_blob.w;
int h = bottom_top_blob.h;
int size = w * h;

int channels_per_group = channels / group;

#pragma omp parallel for num_threads(opt.num_threads)
for (int g = 0; g < group; g++)
{
Mat bottom_top_blob_g = bottom_top_blob.channel_range(g * channels_per_group, channels_per_group);

// mean and var
float sum = 0.f;
for (int q = 0; q < channels_per_group; q++)
{
const float* ptr = bottom_top_blob_g.channel(q);
for (int i = 0; i < size; i++)
{
sum += ptr[i];
}
}
float mean = sum / (channels_per_group * size);

float sqsum = 0.f;
for (int q = 0; q < channels_per_group; q++)
{
const float* ptr = bottom_top_blob_g.channel(q);
for (int i = 0; i < size; i++)
{
float tmp = ptr[i] - mean;
sqsum += tmp * tmp;
}
}
float var = sqsum / (channels_per_group * size);

for (int q = 0; q < channels_per_group; q++)
{
float gamma = gamma_data[g * channels_per_group + q];
float beta = beta_data[g * channels_per_group + q];

float a = static_cast<float>(gamma / sqrt(var + eps));
float b = -mean * a + beta;

float* ptr = bottom_top_blob_g.channel(q);

for (int i = 0; i < size; i++)
{
ptr[i] = ptr[i] * a + b;
}
}
}

return 0;
}

} // namespace ncnn

+ 46
- 0
src/layer/groupnorm.h View File

@@ -0,0 +1,46 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef LAYER_GROUPNORM_H
#define LAYER_GROUPNORM_H

#include "layer.h"

namespace ncnn {

class GroupNorm : public Layer
{
public:
GroupNorm();

virtual int load_param(const ParamDict& pd);

virtual int load_model(const ModelBin& mb);

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

public:
// param
int group;
int channels;
float eps;

// model
Mat gamma_data;
Mat beta_data;
};

} // namespace ncnn

#endif // LAYER_GROUPNORM_H

+ 1
- 1
src/layer/instancenorm.cpp View File

@@ -47,7 +47,7 @@ int InstanceNorm::load_model(const ModelBin& mb)

int InstanceNorm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
// x = (x - mean) / (sqrt(var) + eps) * gamma + beta
// x = (x - mean) / (sqrt(var + eps)) * gamma + beta

int w = bottom_top_blob.w;
int h = bottom_top_blob.h;


+ 1
- 0
tests/CMakeLists.txt View File

@@ -43,6 +43,7 @@ ncnn_add_layer_test(Eltwise)
ncnn_add_layer_test(ELU)
ncnn_add_layer_test(Flatten)
ncnn_add_layer_test(Gemm)
ncnn_add_layer_test(GroupNorm)
ncnn_add_layer_test(HardSigmoid)
ncnn_add_layer_test(HardSwish)
ncnn_add_layer_test(InnerProduct)


+ 57
- 0
tests/test_groupnorm.cpp View File

@@ -0,0 +1,57 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "layer/groupnorm.h"
#include "testutil.h"

static int test_groupnorm(const ncnn::Mat& a, int group, float eps)
{
int channels = a.c;

ncnn::ParamDict pd;
pd.set(0, group);
pd.set(1, channels);
pd.set(2, eps);

std::vector<ncnn::Mat> weights(2);
weights[0] = RandomMat(channels);
weights[1] = RandomMat(channels);

int ret = test_layer<ncnn::GroupNorm>("GroupNorm", pd, weights, a);
if (ret != 0)
{
fprintf(stderr, "test_groupnorm failed a.dims=%d a=(%d %d %d) group=%d eps=%f\n", a.dims, a.w, a.h, a.c, group, eps);
}

return ret;
}

static int test_groupnorm_0()
{
return 0
|| test_groupnorm(RandomMat(6, 4, 2), 1, 0.01f)
|| test_groupnorm(RandomMat(3, 3, 8), 2, 0.002f)
|| test_groupnorm(RandomMat(4, 5, 6), 3, 0.01f)
|| test_groupnorm(RandomMat(5, 6, 12), 4, 0.02f)
|| test_groupnorm(RandomMat(6, 7, 24), 2, 0.001f)
|| test_groupnorm(RandomMat(8, 9, 24), 3, 0.0001f);
}

int main()
{
SRAND(7767517);

return 0
|| test_groupnorm_0();
}

Loading…
Cancel
Save