diff --git a/inference-engine/src/gna_plugin/backend/make_pwl.cpp b/inference-engine/src/gna_plugin/backend/make_pwl.cpp index 597ab304200d43..6c3c3433b08e21 100644 --- a/inference-engine/src/gna_plugin/backend/make_pwl.cpp +++ b/inference-engine/src/gna_plugin/backend/make_pwl.cpp @@ -6,12 +6,58 @@ #include #include -#include -#include +#include "runtime/pwl.h" +#include "gna_slope_scale.h" #include "dnn_types.h" #include "backend/gna_types.h" #include "round_float_define.hpp" + +// This function performes emulatation of HW saturation of PWL segments in SW +// by inserting additional segments when overflow would happen +static void insert_extra_pwl_segments(std::vector& gna_pwl, + const int16_t y_min, + const int16_t y_max) { + std::map extra_segments; + gna_pwl_segment_t extra_segment; + size_t gna_pwl_size = gna_pwl.size(); + + if (gna_pwl_size == 0) + return; + + // We're adding a segment at the beginning if the first one doesn't cover min value + if ((gna_pwl[0].xBase & XBASEMASK) != INT32_MIN) { + extra_segment.xBase = INT32_MIN & XBASEMASK; + extra_segment.yBase = gna_pwl[0].yBase; + extra_segment.slope = 0; + extra_segments[0] = extra_segment; + } + + // We're checking here if saturation could potentially happen at the trailing segments + if (gna_pwl[gna_pwl_size - 1].slope != 0) { + int16_t slope = gna_pwl[gna_pwl_size - 1].slope; + int32_t xBase = gna_pwl[gna_pwl_size - 1].xBase & XBASEMASK; + int16_t yBase = gna_pwl[gna_pwl_size - 1].yBase; + float scale = pow(2, ((gna_pwl[gna_pwl_size - 1].xBase & ~XBASEMASK) + 1) * 8); + float y_value = ((static_cast(INT32_MAX) - xBase) * slope) / scale + yBase; + + if (y_value > static_cast(INT16_MAX) || y_value < static_cast(INT16_MIN)) { + float x_value = ((static_cast(y_max) - yBase) * scale) / slope + xBase; + extra_segment.xBase = FLOAT_TO_INT32(x_value) & XBASEMASK; + extra_segment.yBase = slope > 0 ? y_max : y_min; + extra_segment.slope = 0; + extra_segments[gna_pwl_size] = extra_segment; + } + } + + if (!extra_segments.empty()) + gnalog() << "Additional segment(s) added to protect against saturation\n"; + + for (auto i = extra_segments.rbegin(); i != extra_segments.rend(); i++) { + gna_pwl.insert(gna_pwl.begin() + i->first, i->second); + } +} + void make_gna_pwl(const DnnActivation fun, const std::vector& pwl, const double l_bound, @@ -583,6 +629,7 @@ void make_gna_pwl(const DnnActivation fun, } default: gnalog() << "Unexpected function activation!\n"; - std::cerr << "Unexpected function activation!\n"; + THROW_GNA_EXCEPTION << "Unexpected function activation!" << fun; } + insert_extra_pwl_segments(gna_pwl, y_min, y_max); } diff --git a/inference-engine/src/gna_plugin/backend/make_pwl.hpp b/inference-engine/src/gna_plugin/backend/make_pwl.hpp index 62d95210906d18..5cc879d75ec65a 100644 --- a/inference-engine/src/gna_plugin/backend/make_pwl.hpp +++ b/inference-engine/src/gna_plugin/backend/make_pwl.hpp @@ -5,9 +5,7 @@ #pragma once #include -#include -#include "backend/gna_types.h" - +#include "runtime/pwl.h" void make_gna_pwl(const DnnActivation fun, const std::vector& pwl, diff --git a/inference-engine/src/gna_plugin/runtime/pwl.cpp b/inference-engine/src/gna_plugin/runtime/pwl.cpp index 3cd5238eba658e..89796fbb0cf8a6 100644 --- a/inference-engine/src/gna_plugin/runtime/pwl.cpp +++ b/inference-engine/src/gna_plugin/runtime/pwl.cpp @@ -9,11 +9,10 @@ #include #include #include -#include "backend/gna_types.h" #ifdef _NO_MKL_ #include -#include +#include "backend/make_pwl.hpp" #define SCOPY(num, in, inci, out, inco) for (int i_ = 0; i_ < *(num); i_++) *(out + i_ * *(inco)) = *(in + i_ * *(inci)); #define SSCAL(num, scale, inout, inco) for (int i_ = 0; i_ < *(num); i_++) *(inout + i_ * *(inco)) = *(scale) * *(inout + i_ * *(inco)); @@ -27,7 +26,6 @@ #include "pwl.h" #include "gna_plugin_log.hpp" -#include "backend/dnn_types.h" #include "gna_slope_scale.h" #include "round_float_define.hpp"