1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "ext_list.hpp"
6 #include "ext_base.hpp"
13 #include "ie_parallel.hpp"
15 namespace InferenceEngine {
16 namespace Extensions {
19 class ReverseSequenceImpl: public ExtLayerBase {
21 explicit ReverseSequenceImpl(const CNNLayer* layer) {
23 if (layer->insData.size() != 2 || layer->outData.size() != 1)
24 THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output edges!";
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";
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!";
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!";
43 seq_axis = layer->GetParamAsInt("seq_axis", 1);
45 seq_axis += src_dims.size();
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!";
50 batch_axis = layer->GetParamAsInt("batch_axis", 0);
52 batch_axis += src_dims.size();
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!";
57 if (seq_lengths_dims[0] != dst_dims[batch_axis])
58 THROW_IE_EXCEPTION << layer->name << " Incorrect 'seq_lengths_dims' parameters dimension!";
60 srcStrides = layer->insData[REVERSESEQUENCE_DATA].lock()->getTensorDesc().getBlockingDesc().getStrides();
61 work_amount_dst = srcStrides[0] * src_dims[0];
63 addConfig(layer, { DataConfigurator(ConfLayout::PLN), DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) });
64 } catch (InferenceEngine::details::InferenceEngineException &ex) {
69 StatusCode execute(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
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();
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])) {
83 std::string errorMsg = "Incorrect input 'seq_lengths' values!";
84 errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
86 return PARAMETER_MISMATCH;
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];
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;
106 src_idx += idx * srcStrides[i];
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;
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])) {
123 std::string errorMsg = "Incorrect input 'seq_lengths' values!";
124 errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
126 return PARAMETER_MISMATCH;
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];
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;
146 src_idx += idx * srcStrides[i];
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;
158 return GENERAL_ERROR;
165 const size_t REVERSESEQUENCE_DATA = 0;
166 const size_t REVERSESEQUENCE_LENGTHS = 1;
171 SizeVector srcStrides;
172 size_t work_amount_dst;
175 REG_FACTORY_FOR(ImplFactory<ReverseSequenceImpl>, ReverseSequence);
178 } // namespace Extensions
179 } // namespace InferenceEngine