[IE CLDNN] Added HSigmoid operation (#2700)
authorRoman Lyamin <Roman.Lyamin@intel.com>
Sun, 18 Oct 2020 17:47:22 +0000 (20:47 +0300)
committerGitHub <noreply@github.com>
Sun, 18 Oct 2020 17:47:22 +0000 (20:47 +0300)
12 files changed:
inference-engine/src/cldnn_engine/cldnn_program.cpp
inference-engine/src/cldnn_engine/cldnn_program.h
inference-engine/tests/functional/plugin/gpu/shared_tests_instances/single_layer_tests/activation.cpp
inference-engine/tests/functional/plugin/shared/include/single_layer_tests/activation.hpp
inference-engine/tests/ngraph_functions/include/ngraph_functions/utils/ngraph_helpers.hpp
inference-engine/tests/ngraph_functions/src/activation.cpp
inference-engine/thirdparty/clDNN/api/activation.hpp
inference-engine/thirdparty/clDNN/kernel_selector/common/common_types.h
inference-engine/thirdparty/clDNN/kernel_selector/core/common/jitter.cpp
inference-engine/thirdparty/clDNN/kernel_selector/core/kernel_selector_common.cpp
inference-engine/thirdparty/clDNN/src/kernel_selector_helper.cpp
inference-engine/thirdparty/clDNN/tests/test_cases/activation_simple_gpu_test.cpp

index cda4ab7..28a2529 100644 (file)
@@ -830,6 +830,7 @@ Program::LayerType Program::LayerTypeFromStr(const std::string &str) {
         { "Ceiling" , Ceiling },
         { "Erf" , Erf },
         { "HardSigmoid" , HardSigmoid },
+        { "HSigmoid", HSigmoid },
         { "Log" , Log },
         { "Neg" , Neg },
         { "Reciprocal" , Reciprocal },
@@ -1399,6 +1400,7 @@ void Program::CreateSingleLayerPrimitive(cldnn::topology& topology, InferenceEng
         case Ceiling:
         case Erf:
         case HardSigmoid:
+        case HSigmoid:
         case Log:
         case Neg:
         case Reciprocal:
@@ -3078,6 +3080,8 @@ void Program::CreateActivationPrimitive(cldnn::topology& topology, InferenceEngi
             activationType = Exp;
         } else if (activation_type == "not")  {
             activationType = Not;
+        } else if (activation_type == "hsigmoid")  {
+            activationType = HSigmoid;
         } else {
             THROW_CLDNN_EXCEPTION("Unsupported activation type (" + activation_type +
                                   ") in layer " + layer->name);
@@ -3199,6 +3203,11 @@ void Program::CreateActivationPrimitive(cldnn::topology& topology, InferenceEngi
         params.b = layer->GetParamAsFloat("beta", 0.5f);
         break;
     }
+    case HSigmoid:
+    {
+        func = cldnn::activation_func::hsigmoid;
+        break;
+    }
     case Log:
     {
         func = cldnn::activation_func::log;
index 67a466c..ed67755 100644 (file)
@@ -195,6 +195,7 @@ public:
         Ceiling,
         Erf,
         HardSigmoid,
+        HSigmoid,
         Log,
         Neg,
         Reciprocal,
index 6584d24..154a998 100644 (file)
@@ -44,7 +44,8 @@ const std::map<ActivationTypes, std::vector<std::vector<float>>> activationTypes
         {Ceiling,     {}},
         {Mish,        {}},
         {HSwish,      {}},
-        {SoftPlus,    {}}
+        {SoftPlus,    {}},
+        {HSigmoid,    {}}
 };
 
 std::map<std::vector<size_t>, std::vector<std::vector<size_t>>> basic = {
index 44b0247..bbf6e9f 100644 (file)
@@ -71,6 +71,7 @@ static std::map<ngraph::helpers::ActivationTypes, std::string> activationNames =
         {ngraph::helpers::ActivationTypes::HSwish,      "HSwish"},
         {ngraph::helpers::ActivationTypes::SoftPlus,    "SoftPlus"},
         {ngraph::helpers::ActivationTypes::Swish,       "Swish"},
+        {ngraph::helpers::ActivationTypes::HSigmoid,    "HSigmoid"},
 };
 
 typedef std::tuple<
index c09df34..cbccfb6 100644 (file)
@@ -102,6 +102,8 @@ std::shared_ptr<ngraph::Node> makeActivation(const ngraph::Output<Node> &in,
             auto beta = std::make_shared<ngraph::op::Constant>(type, inShape, constantsValue[0]);
             return std::make_shared<ngraph::op::v4::Swish>(in, beta);
         }
+        case ngraph::helpers::ActivationTypes::HSigmoid:
+            return std::make_shared<ngraph::op::v5::HSigmoid>(in);
         default:
             throw std::runtime_error("Can't create layer for this activation type");
     }
index 9b892d6..ce5d8e8 100644 (file)
@@ -63,6 +63,7 @@ enum class activation_func {
     reciprocal,           // (1/val)
     erf,                  // Gauss error function
     hard_sigmoid,         // max(0, min(1, a * val + b))       (a,b are additional params)
+    hsigmoid,             // min(max(val + 3, 0), 6) / 6
     selu,                 // for val <= 0: b * (a * e^val - a); for val > 0: b * val (a,b are additional params)
     sign,                 // val > 0: 1; val < 0: -1; val == 0: 0
     softplus,             // ln(exp(val) + 1)
index 85a2793..2828374 100644 (file)
@@ -145,6 +145,7 @@ enum class ActivationFunction {
     POW,
     ERF,
     HARD_SIGMOID,
+    HSIGMOID,
     RECIPROCAL,
     SELU,
     SIGN,
index 5240434..d566440 100644 (file)
@@ -584,7 +584,7 @@ class WeightTensorJitConstant : public TensorBaseTJitConstant<WeightsType, Weigh
             } else if (l == WeightsLayout::g_os_zyx_is_osv16_isv16 || l == WeightsLayout::g_os_zyx_is_osv16_isv32 ||
                        l == WeightsLayout::g_os_zyx_is_osv32_isv16 || l == WeightsLayout::g_os_zyx_is_osv32_isv32) {
                 args macroNameArgs = {"prefix", "g", "o", "i", "z", "y", "x"};
-                args funcArgs = {"g", "o", "i", "z", "y", "x", "g_size", "o_size", "i_size", "z_size", "y_size", "x_size", "osv", "isv"};                
+                args funcArgs = {"g", "o", "i", "z", "y", "x", "g_size", "o_size", "i_size", "z_size", "y_size", "x_size", "osv", "isv"};
                 const auto name = toString(l);
                 const auto body = R"V0G0N( \
     uint is_size = (i_size + isv - 1) / isv; \
@@ -615,7 +615,7 @@ class WeightTensorJitConstant : public TensorBaseTJitConstant<WeightsType, Weigh
                 this->macroName = MacroName(name, macroNameArgs);
                 this->calcFunction = FuncBody(name, funcArgs, body);
                 std::string osv = "16", isv = "16";
-                if (l == WeightsLayout::g_os_zyx_is_osv16_isv16) { 
+                if (l == WeightsLayout::g_os_zyx_is_osv16_isv16) {
                     osv = "16"; isv = "16";
                 } else if (l == WeightsLayout::g_os_zyx_is_osv16_isv32) {
                     osv = "16"; isv = "32";
@@ -741,7 +741,7 @@ JitDefinitions WeightTensorJitConstant::GetDefinitions() const {
             if (is_grouped_4d_layout) {
                 index_macro_name = _name + "_GET_INDEX(g, o, i, y, x)";
                 auto layout_str = toString(layout);
-                if (layout == WeightsLayout::goiyx) 
+                if (layout == WeightsLayout::goiyx)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", g, o, i, 0, y, x)";
                 else if (layout == WeightsLayout::g_os_is_yx_isv16_osv16)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", g, o, i, 0, y, x, 16)";
@@ -765,7 +765,7 @@ JitDefinitions WeightTensorJitConstant::GetDefinitions() const {
             if (is_grouped_5d_layout) {
                 index_macro_name = _name + "_GET_INDEX(g, o, i, z, y, x)";
                 auto layout_str = toString(layout);
-                if (layout == WeightsLayout::goizyx) 
+                if (layout == WeightsLayout::goizyx)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", g, o, i, z, y, x)";
                 else if (layout == WeightsLayout::g_os_is_zyx_isv16_osv16)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", g, o, i, z, y, x, 16)";
@@ -787,7 +787,7 @@ JitDefinitions WeightTensorJitConstant::GetDefinitions() const {
             if (is_common_4d_layout) {
                 index_macro_name = _name + "_GET_INDEX(o, i, y, x)";
                 auto layout_str = toString(layout);
-                if (layout == WeightsLayout::oiyx) 
+                if (layout == WeightsLayout::oiyx)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", 0, o, i, 0, y, x)";
                 else if (layout == WeightsLayout::os_is_yx_isv16_osv16)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", 0, o, i, 0, y, x, 16)";
@@ -814,7 +814,7 @@ JitDefinitions WeightTensorJitConstant::GetDefinitions() const {
             if (is_common_5d_layout) {
                 index_macro_name = _name + "_GET_INDEX(o, i, z, y, x)";
                 auto layout_str = toString(layout);
-                if (layout == WeightsLayout::oizyx) 
+                if (layout == WeightsLayout::oizyx)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", 0, o, i, z, y, x)";
                 else if (layout == WeightsLayout::os_is_zyx_isv16_osv16)
                     index_func_val = "GET_WEIGHTS_" + layout_str + "_INDEX(" + _name + ", 0, o, i, z, y, x, 16)";
@@ -1022,6 +1022,15 @@ JitConstants MakeActivationJitConstants(ActivationFunction activation_function,
                     max_func(zero, min_func(one, (JitTerm)((alpha * input + beta).str()))).str()));
             break;
         }
+        case ActivationFunction::HSIGMOID: {
+            std::string type_suffix = out_dt == Datatype::F32 ? "f" : "h";
+            const JitTerm three("3." + type_suffix);
+            const JitTerm six("6." + type_suffix);
+            jitConstants.AddConstant(MakeJitConstant(
+                    macro_def,
+                    (min_func(max_func(zero, input + three), six) / six).str()));
+            break;
+        }
         case ActivationFunction::SIGN:
             jitConstants.AddConstant(MakeJitConstant(
                     macro_def,
index 95bac97..c2a4998 100644 (file)
@@ -76,6 +76,7 @@ std::string toString(ActivationFunction activation) {
         case ActivationFunction::NEGATIVE:                 method = "NEGATIVE"; break;
         case ActivationFunction::ERF:                      method = "ERF"; break;
         case ActivationFunction::HARD_SIGMOID:             method = "HARD_SIGMOID"; break;
+        case ActivationFunction::HSIGMOID:                 method = "HSIGMOID"; break;
         case ActivationFunction::RECIPROCAL:               method = "RECIPROCAL"; break;
         case ActivationFunction::SELU:                     method = "SELU"; break;
         case ActivationFunction::SIGN:                     method = "SIGN"; break;
index c0e0683..0d6f168 100644 (file)
@@ -693,6 +693,8 @@ kernel_selector::activation_function get_kernel_selector_activation_param(activa
             return kernel_selector::activation_function::SOFTSIGN;
         case cldnn::activation_func::hard_sigmoid:
             return kernel_selector::activation_function::HARD_SIGMOID;
+        case cldnn::activation_func::hsigmoid:
+            return kernel_selector::activation_function::HSIGMOID;
         case cldnn::activation_func::swish:
             return kernel_selector::activation_function::SWISH;
         case cldnn::activation_func::hswish:
index 8c801b5..5f99ac8 100644 (file)
@@ -735,6 +735,46 @@ TEST(activation_f16_fw_gpu, basic_yxfb_hswish) {
     }
 }
 
+TEST(activation_f16_fw_gpu, basic_yxfb_hsigmoid) {
+    const auto& engine = get_test_engine();
+
+    auto input = memory::allocate(engine, { data_types::f16, format::yxfb, { 1, 2, 5, 2 } });
+    set_values(input,
+    { FLOAT16(0.0f), FLOAT16(-2.0f), FLOAT16(-3.0f), FLOAT16(4.0f), FLOAT16(5.0f),
+      FLOAT16(2.0f), FLOAT16(2.0f), FLOAT16(3.0f), FLOAT16(4.0f), FLOAT16(-6.0f),
+      FLOAT16(3.0f), FLOAT16(-3.0f), FLOAT16(3.0f), FLOAT16(5.0f), FLOAT16(1.0f),
+      FLOAT16(1.0f), FLOAT16(1.0f), FLOAT16(1.0f), FLOAT16(-1.0f), FLOAT16(1.0f) });
+
+    topology topology(
+        input_layout("input", input.get_layout()),
+        activation("hsigmoid", "input", activation_func::hsigmoid));
+    network network(engine, topology);
+    network.set_input_data("input", input);
+    auto outputs = network.execute();
+    EXPECT_EQ(outputs.size(), size_t(1));
+    EXPECT_EQ(outputs.begin()->first, "hsigmoid");
+
+    auto output_memory = outputs.at("hsigmoid").get_memory();
+    auto output_layout = output_memory.get_layout();
+    auto output_ptr = output_memory.pointer<FLOAT16>();
+    auto input_ptr = input.pointer<FLOAT16>();
+
+    int y_size = output_layout.size.spatial[1];
+    int x_size = output_layout.size.spatial[0];
+    int f_size = output_layout.size.feature[0];
+    int b_size = output_layout.size.batch[0];
+    EXPECT_EQ(output_layout.format, format::yxfb);
+    EXPECT_EQ(y_size, 2);
+    EXPECT_EQ(x_size, 5);
+    EXPECT_EQ(f_size, 2);
+    EXPECT_EQ(b_size, 1);
+
+    for (size_t i = 0; i < output_layout.get_linear_size(); ++i) {
+        EXPECT_NEAR((FLOAT16)(std::fmin(std::fmax(0.f, (float)input_ptr[i] + 3.f), 6.f) / 6.f),
+                    output_ptr[i], 1e-3f);
+    }
+}
+
 TEST(activation_f32_fw_gpu, basic_yxfb_all_functions)
 {
     //  Input:
@@ -782,7 +822,8 @@ TEST(activation_f32_fw_gpu, basic_yxfb_all_functions)
         activation_func::swish,
         activation_func::hswish,
         activation_func::mish,
-        activation_func::gelu
+        activation_func::gelu,
+        activation_func::hsigmoid
     };
 
     activation_additional_params params = { 0.5f, 2.5f };
@@ -910,6 +951,9 @@ TEST(activation_f32_fw_gpu, basic_yxfb_all_functions)
                     EXPECT_NEAR(0.5f * (float)input_ptr[i] * (1.f + std::erf((float)(input_ptr[i]) / std::sqrt(2.0f))),
                                 output_ptr[i], 1e-5f);
                     break;
+                case activation_func::hsigmoid:
+                    EXPECT_FLOAT_EQ(std::fmin(std::fmax(0.f, (float)input_ptr[i] + 3.f), 6.f) / 6.f, output_ptr[i]);
+                    break;
                 default:
                     break;
                 }