Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / extension / ext_reverse_sequence.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 <algorithm>
13 #include "ie_parallel.hpp"
14
15 namespace InferenceEngine {
16 namespace Extensions {
17 namespace Cpu {
18
19 class ReverseSequenceImpl: public ExtLayerBase {
20 public:
21     explicit ReverseSequenceImpl(const CNNLayer* layer) {
22         try {
23             if (layer->insData.size() != 2 || layer->outData.size() != 1)
24                 THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output edges!";
25
26             src_dims = layer->insData[REVERSESEQUENCE_DATA].lock()->getTensorDesc().getDims();
27             SizeVector seq_lengths_dims = layer->insData[REVERSESEQUENCE_LENGTHS].lock()->getTensorDesc().getDims();
28             if (layer->insData[REVERSESEQUENCE_LENGTHS].lock()->getTensorDesc().getPrecision() != Precision::I32 &&
29                 layer->insData[REVERSESEQUENCE_LENGTHS].lock()->getTensorDesc().getPrecision() != Precision::FP32)
30                 THROW_IE_EXCEPTION << layer->name << " Incorrect 'seq_lengths' input precision. Only FP32 and I32 are supported!";
31             if (seq_lengths_dims.size() > 1)
32                 THROW_IE_EXCEPTION << layer->name << " Seq_lengths vector should be 1 dimension";
33
34             SizeVector dst_dims = layer->outData[0]->getTensorDesc().getDims();
35             if (src_dims.size() != dst_dims.size())
36                 THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output sizes!";
37
38             for (size_t i = 0; i < dst_dims.size(); i++) {
39                 if (src_dims[i] != dst_dims[i])
40                     THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output dimension!";
41             }
42
43             seq_axis = layer->GetParamAsInt("seq_axis", 1);
44             if (seq_axis < 0)
45                 seq_axis += src_dims.size();
46
47             if (seq_axis < 0 || seq_axis >= static_cast<int>(src_dims.size()))
48                 THROW_IE_EXCEPTION << layer->name << " Incorrect 'seq_axis' parameters dimensions and axis number!";
49
50             batch_axis = layer->GetParamAsInt("batch_axis", 0);
51             if (batch_axis < 0)
52                 batch_axis += src_dims.size();
53
54             if (batch_axis < 0 || batch_axis >= static_cast<int>(src_dims.size()))
55                 THROW_IE_EXCEPTION << layer->name << " Incorrect 'batch_axis' parameters dimensions and axis number!";
56
57             if (seq_lengths_dims[0] != dst_dims[batch_axis])
58                 THROW_IE_EXCEPTION << layer->name << " Incorrect 'seq_lengths_dims' parameters dimension!";
59
60             srcStrides = layer->insData[REVERSESEQUENCE_DATA].lock()->getTensorDesc().getBlockingDesc().getStrides();
61             work_amount_dst = srcStrides[0] * src_dims[0];
62
63             addConfig(layer, { DataConfigurator(ConfLayout::PLN), DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) });
64         } catch (InferenceEngine::details::InferenceEngineException &ex) {
65             errorMsg = ex.what();
66         }
67     }
68
69     StatusCode execute(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
70         size_t i;
71         const float *src_data = inputs[REVERSESEQUENCE_DATA]->cbuffer().as<const float *>() +
72                                 inputs[REVERSESEQUENCE_DATA]->getTensorDesc().getBlockingDesc().getOffsetPadding();
73         float* dst_data = outputs[0]->cbuffer().as<float *>() +
74                           outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
75
76         switch (inputs[REVERSESEQUENCE_LENGTHS]->precision()) {
77             case Precision::FP32: {
78                 float *seq_lengths_data = inputs[REVERSESEQUENCE_LENGTHS]->cbuffer().as<float *>() +
79                                           inputs[REVERSESEQUENCE_LENGTHS]->getTensorDesc().getBlockingDesc().getOffsetPadding();
80                 for (i = 0; i < src_dims[batch_axis]; i++) {
81                     if (static_cast<int32_t>(seq_lengths_data[i]) > static_cast<int>(src_dims[seq_axis])) {
82                         if (resp) {
83                             std::string errorMsg = "Incorrect input 'seq_lengths' values!";
84                             errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
85                         }
86                         return PARAMETER_MISMATCH;
87                     }
88                 }
89
90                 parallel_nt(0, [&](const int ithr, const int nthr) {
91                     size_t i, start = 0, end = 0, src_idx = 0;
92                     SizeVector counters(src_dims.size(), 0);
93                     splitter(work_amount_dst, nthr, ithr, start, end);
94                     for (int j = src_dims.size() - 1, i = start; j >= 0; j--) {
95                         counters[j] = i % src_dims[j];
96                         i /= src_dims[j];
97                     }
98
99                     for (size_t iwork = start; iwork < end; ++iwork) {
100                         for (i = 0, src_idx = 0; i < src_dims.size(); ++i) {
101                             size_t idx = counters[i];
102                             if (static_cast<int>(i) == seq_axis &&
103                                     static_cast<int>(idx) < static_cast<int32_t>(seq_lengths_data[counters[batch_axis]])) {
104                                 idx = static_cast<int32_t>(seq_lengths_data[counters[batch_axis]]) - idx - 1;
105                             }
106                             src_idx += idx * srcStrides[i];
107                         }
108                         dst_data[iwork] = src_data[src_idx];
109                         for (int j = src_dims.size() - 1; j >= 0; j--) {
110                             counters[j] = (counters[j] + 1) % src_dims[j];
111                             if (counters[j] != 0) break;
112                         }
113                     }
114                 });
115             }
116             break;
117             case Precision::I32: {
118                 int32_t *seq_lengths_data = inputs[REVERSESEQUENCE_LENGTHS]->cbuffer().as<int32_t *>() +
119                                             inputs[REVERSESEQUENCE_LENGTHS]->getTensorDesc().getBlockingDesc().getOffsetPadding();
120                 for (i = 0; i < src_dims[batch_axis]; i++) {
121                     if (seq_lengths_data[i] > static_cast<int>(src_dims[seq_axis])) {
122                         if (resp) {
123                             std::string errorMsg = "Incorrect input 'seq_lengths' values!";
124                             errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
125                         }
126                         return PARAMETER_MISMATCH;
127                     }
128                 }
129
130                 parallel_nt(0, [&](const int ithr, const int nthr) {
131                     size_t i, start = 0, end = 0, src_idx = 0;
132                     SizeVector counters(src_dims.size(), 0);
133                     splitter(work_amount_dst, nthr, ithr, start, end);
134                     for (int j = src_dims.size() - 1, i = start; j >= 0; j--) {
135                         counters[j] = i % src_dims[j];
136                         i /= src_dims[j];
137                     }
138
139                     for (size_t iwork = start; iwork < end; ++iwork) {
140                         for (i = 0, src_idx = 0; i < src_dims.size(); ++i) {
141                             size_t idx = counters[i];
142                             if (static_cast<int>(i) == seq_axis &&
143                                     static_cast<int>(idx) < seq_lengths_data[counters[batch_axis]]) {
144                                 idx = seq_lengths_data[counters[batch_axis]] - idx - 1;
145                             }
146                             src_idx += idx * srcStrides[i];
147                         }
148                         dst_data[iwork] = src_data[src_idx];
149                         for (int j = src_dims.size() - 1; j >= 0; j--) {
150                             counters[j] = (counters[j] + 1) % src_dims[j];
151                             if (counters[j] != 0) break;
152                         }
153                     }
154                 });
155             }
156             break;
157             default:
158                 return GENERAL_ERROR;
159         }
160
161         return OK;
162     }
163
164 private:
165     const size_t REVERSESEQUENCE_DATA = 0;
166     const size_t REVERSESEQUENCE_LENGTHS = 1;
167
168     int seq_axis;
169     int batch_axis;
170     SizeVector src_dims;
171     SizeVector srcStrides;
172     size_t work_amount_dst;
173 };
174
175 REG_FACTORY_FOR(ImplFactory<ReverseSequenceImpl>, ReverseSequence);
176
177 }  // namespace Cpu
178 }  // namespace Extensions
179 }  // namespace InferenceEngine