| @@ -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) | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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; | |||
| @@ -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) | |||
| @@ -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(); | |||
| } | |||