Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / extension / ext_range.cpp
1 // Copyright (C) 2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "ext_list.hpp"
6 #include "ext_base.hpp"
7
8 #include <cmath>
9 #include <string>
10 #include <vector>
11 #include <cassert>
12 #include "ie_parallel.hpp"
13
14 namespace InferenceEngine {
15 namespace Extensions {
16 namespace Cpu {
17
18 class RangeImpl: public ExtLayerBase {
19 public:
20     explicit RangeImpl(const CNNLayer* layer) {
21         try {
22             if (layer->insData.empty() || layer->outData.empty())
23                 THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output edges!";
24
25             if (layer->insData.size() != 3)
26                 THROW_IE_EXCEPTION << layer->name << " Incorrect number of input edges!";
27
28             SizeVector start_dims = layer->insData[RANGE_START].lock()->getTensorDesc().getDims();
29             if (start_dims.size() > 1)
30                 THROW_IE_EXCEPTION << layer->name << " Start scalar should have 1 dimension";
31
32             SizeVector limit_dims = layer->insData[RANGE_LIMIT].lock()->getTensorDesc().getDims();
33             if (limit_dims.size() > 1)
34                 THROW_IE_EXCEPTION << layer->name << " Limit scalar should have 1 dimension";
35
36             SizeVector delta_dims = layer->insData[RANGE_DELTA].lock()->getTensorDesc().getDims();
37             if (delta_dims.size() > 1)
38                 THROW_IE_EXCEPTION << layer->name << " Delta scalar should have 1 dimension";
39
40             SizeVector dst_dims = layer->outData[0]->getTensorDesc().getDims();
41             if (dst_dims.size() > 1)
42                 THROW_IE_EXCEPTION << layer->name << " Output vector should have 1 dimension";
43
44             if (!(layer->insData[RANGE_START].lock()->getTensorDesc().getPrecision() == Precision::I32 &&
45                   layer->insData[RANGE_LIMIT].lock()->getTensorDesc().getPrecision() == Precision::I32 &&
46                   layer->insData[RANGE_DELTA].lock()->getTensorDesc().getPrecision() == Precision::I32 &&
47                   layer->outData[0]->getTensorDesc().getPrecision() == Precision::I32) &&
48                 !(layer->insData[RANGE_START].lock()->getTensorDesc().getPrecision() == Precision::FP32 &&
49                   layer->insData[RANGE_LIMIT].lock()->getTensorDesc().getPrecision() == Precision::FP32 &&
50                   layer->insData[RANGE_DELTA].lock()->getTensorDesc().getPrecision() == Precision::FP32 &&
51                   layer->outData[0]->getTensorDesc().getPrecision() == Precision::FP32)) {
52                 THROW_IE_EXCEPTION << layer->name <<
53                     " 'Start', 'Limit', 'Delta' input scalars and output tensor should have same precision" <<
54                     "and only FP32 and I32 are supported!";
55             }
56
57             addConfig(layer, { DataConfigurator(ConfLayout::PLN), DataConfigurator(ConfLayout::PLN), DataConfigurator(ConfLayout::PLN) },
58                              { DataConfigurator(ConfLayout::PLN) });
59         } catch (InferenceEngine::details::InferenceEngineException &ex) {
60             errorMsg = ex.what();
61         }
62     }
63
64     StatusCode execute(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
65         StatusCode retcode = OK;
66         switch (outputs[0]->precision()) {
67         case Precision::FP32: {
68             retcode = range((inputs[RANGE_START]->cbuffer().as<float *>() +
69                              inputs[RANGE_START]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0],
70                             (inputs[RANGE_LIMIT]->cbuffer().as<float *>() +
71                              inputs[RANGE_LIMIT]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0],
72                             (inputs[RANGE_DELTA]->cbuffer().as<float *>() +
73                              inputs[RANGE_DELTA]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0], outputs[0]);
74         }
75         break;
76         case Precision::I32: {
77             retcode = range((inputs[RANGE_START]->cbuffer().as<int32_t *>() +
78                              inputs[RANGE_START]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0],
79                             (inputs[RANGE_LIMIT]->cbuffer().as<int32_t *>() +
80                              inputs[RANGE_LIMIT]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0],
81                             (inputs[RANGE_DELTA]->cbuffer().as<int32_t *>() +
82                              inputs[RANGE_DELTA]->getTensorDesc().getBlockingDesc().getOffsetPadding())[0], outputs[0]);
83         }
84         break;
85         default:
86             if (resp) {
87                 std::string errorMsg = "Incorrect output precision. Only FP32 and I32 are supported!";
88                 errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
89             }
90             retcode = GENERAL_ERROR;
91         }
92         if (resp && retcode == PARAMETER_MISMATCH) {
93             std::string errorMsg = "Range indexes exceeds data tensor dimension";
94             errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
95         }
96         return retcode;
97     }
98
99 private:
100     const size_t RANGE_START = 0;
101     const size_t RANGE_LIMIT = 1;
102     const size_t RANGE_DELTA = 2;
103
104     template <typename data_t>
105     StatusCode range(data_t start, data_t limit, data_t delta, Blob::Ptr output);
106 };
107
108 template <typename data_t>
109 StatusCode RangeImpl::range(data_t start, data_t limit, data_t delta, Blob::Ptr output) {
110     size_t dst_size = (output->getTensorDesc().getDims())[0];
111     data_t* dst_data = output->cbuffer().as<data_t *>() +
112                        output->getTensorDesc().getBlockingDesc().getOffsetPadding();
113     size_t work_amount_dst = static_cast<size_t>(std::floor(std::abs((limit - start) / delta)));
114     if (work_amount_dst != dst_size)
115         return PARAMETER_MISMATCH;
116
117     parallel_nt(0, [&](const int ithr, const int nthr) {
118         size_t iwork = 0, end = 0;
119         splitter(work_amount_dst, nthr, ithr, iwork, end);
120         data_t dst_value = start + iwork * delta;
121
122         for (; iwork < end; ++iwork, dst_value += delta) {
123             dst_data[iwork] = dst_value;
124         }
125     });
126     return OK;
127 }
128 REG_FACTORY_FOR(ImplFactory<RangeImpl>, Range);
129
130 }  // namespace Cpu
131 }  // namespace Extensions
132 }  // namespace InferenceEngine