Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/dnn/src/layers/permute_layer.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14
// Copyright (C) 2017, Intel Corporation, all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
#include "../precomp.hpp"
44
#include "layers_common.hpp"
45
#include "../op_inf_engine.hpp"
46
#include "../op_vkcom.hpp"
47
#include <float.h>
48
#include <algorithm>
49
50
#ifdef HAVE_OPENCL
51
#include "opencl_kernels_dnn.hpp"
52
#endif
53
54
namespace cv
55
{
56
namespace dnn
57
{
58
class PermuteLayerImpl CV_FINAL : public PermuteLayer
59
{
60
public:
61
void checkNeedForPermutation()
62
{
63
_needsPermute = false;
64
for (size_t i = 0; i < _numAxes; ++i)
65
{
66
if (_order[i] != i)
67
{
68
_needsPermute = true;
69
break;
70
}
71
}
72
}
73
74
PermuteLayerImpl(const LayerParams &params)
75
: _count(0), _needsPermute(false), _numAxes(0)
76
{
77
if (!params.has("order"))
78
{
79
return;
80
}
81
82
DictValue paramOrder = params.get("order");
83
_numAxes = paramOrder.size();
84
85
for (size_t i = 0; i < _numAxes; i++)
86
{
87
int currentOrder = paramOrder.get<int>(i);
88
if (currentOrder < 0 || currentOrder > _numAxes)
89
{
90
CV_Error(Error::StsBadArg,
91
format("Orders of dimensions in Permute layer parameter"
92
"must be in [0...%zu]", _numAxes - 1));
93
}
94
if (std::find(_order.begin(), _order.end(), currentOrder) != _order.end())
95
{
96
CV_Error(Error::StsBadArg,
97
"Permute layer parameter contains duplicated orders.");
98
}
99
_order.push_back(currentOrder);
100
}
101
102
setParamsFrom(params);
103
checkNeedForPermutation();
104
}
105
106
virtual bool supportBackend(int backendId) CV_OVERRIDE
107
{
108
return backendId == DNN_BACKEND_OPENCV ||
109
backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() ||
110
backendId == DNN_BACKEND_VKCOM && haveVulkan();
111
}
112
113
bool getMemoryShapes(const std::vector<MatShape> &inputs,
114
const int requiredOutputs,
115
std::vector<MatShape> &outputs,
116
std::vector<MatShape> &internals) const CV_OVERRIDE
117
{
118
if(!_needsPermute)
119
{
120
Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals);
121
return true;
122
}
123
124
CV_Assert(inputs.size() > 0);
125
CV_Assert((int)_numAxes == inputs[0].size());
126
127
MatShape shapeBefore = inputs[0], shapeAfter;
128
for (size_t i = 0; i < _numAxes; i++)
129
{
130
shapeAfter.push_back(shapeBefore[_order[i]]);
131
}
132
133
outputs.clear();
134
135
for (size_t i = 0; i < inputs.size(); i++)
136
{
137
CV_Assert(total(inputs[i]) == total(shapeAfter));
138
outputs.push_back(shapeAfter);
139
}
140
141
return false;
142
}
143
144
void computeStrides(const MatShape &shapeBefore, const MatShape &shapeAfter)
145
{
146
_oldStride.resize(_numAxes);
147
_newStride.resize(_numAxes);
148
149
_oldStride[_numAxes - 1] = 1;
150
_newStride[_numAxes - 1] = 1;
151
152
for(int i = _numAxes - 2; i >= 0; i--)
153
{
154
_oldStride[i] = _oldStride[i + 1] * shapeBefore[i + 1];
155
_newStride[i] = _newStride[i + 1] * shapeAfter[i + 1];
156
}
157
158
_count = _oldStride[0] * shapeBefore[0];
159
}
160
161
void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE
162
{
163
if(!_needsPermute)
164
{
165
return;
166
}
167
std::vector<Mat> inputs, outputs;
168
inputs_arr.getMatVector(inputs);
169
outputs_arr.getMatVector(outputs);
170
171
CV_Assert(inputs.size() > 0);
172
const Mat& inp0 = inputs[0];
173
CV_Assert((int)_numAxes == inp0.dims);
174
175
computeStrides(shape(inputs[0]), shape(outputs[0]));
176
177
#ifdef HAVE_OPENCL
178
if (uorder.empty())
179
{
180
std::vector<int> orderVec(_order.begin(), _order.end());;
181
Mat morder(1, orderVec.size(), CV_32SC1, &orderVec[0]);
182
183
std::vector<int> oldStrideVec(_oldStride.begin(), _oldStride.end());
184
Mat mold_stride(1, _oldStride.size(), CV_32SC1, &oldStrideVec[0]);
185
186
std::vector<int> newStrideVec(_newStride.begin(), _newStride.end());
187
Mat mnew_stride(1, newStrideVec.size(), CV_32SC1, &newStrideVec[0]);
188
189
morder.copyTo(uorder);
190
mold_stride.copyTo(uold_stride);
191
mnew_stride.copyTo(unew_stride);
192
}
193
#endif
194
}
195
196
class PermuteInvoker : public ParallelLoopBody
197
{
198
public:
199
const Mat* inp;
200
Mat* out;
201
const std::vector<size_t>* order;
202
int nstripes;
203
204
static void run(const Mat& inp, Mat& out, const std::vector<size_t>& order, int nstripes)
205
{
206
PermuteInvoker p;
207
p.inp = &inp;
208
p.out = &out;
209
p.order = &order;
210
p.nstripes = nstripes;
211
212
CV_Assert( out.size[0] == inp.size[order[0]] &&
213
out.size[1] == inp.size[order[1]] &&
214
out.size[2] == inp.size[order[2]] &&
215
out.size[3] == inp.size[order[3]]);
216
217
parallel_for_(Range(0, nstripes), p, nstripes);
218
}
219
220
PermuteInvoker() : inp(0), out(0), order(0), nstripes(0) {}
221
222
void operator()(const Range& r) const CV_OVERRIDE
223
{
224
int n0 = out->size[0], n1 = out->size[1], n2 = out->size[2], n3 = out->size[3];
225
226
size_t orows = (size_t)n0*n1*n2;
227
size_t stripeSize = (orows + nstripes - 1)/nstripes;
228
size_t stripeStart = r.start*stripeSize;
229
size_t stripeEnd = std::min(r.end*stripeSize, orows);
230
231
const size_t esz = sizeof(float);
232
size_t ostep0 = out->step[0]/esz, ostep1 = out->step[1]/esz, ostep2 = out->step[2]/esz;
233
const size_t* ord = &order->at(0);
234
size_t istep0 = inp->step[ord[0]]/esz, istep1 = inp->step[ord[1]]/esz,
235
istep2 = inp->step[ord[2]]/esz, istep3 = inp->step[ord[3]]/esz;
236
237
size_t val = stripeStart;
238
int i2 = (int)(val % n2);
239
val /= n2;
240
int i1 = (int)(val % n1);
241
int i0 = (int)(val / n1);
242
243
const float* inptr_orig = inp->ptr<float>();
244
float* outptr_orig = out->ptr<float>();
245
246
for( size_t ofs = stripeStart; ofs < stripeEnd; ofs++ )
247
{
248
const float* inptr = inptr_orig + i0*istep0 + i1*istep1 + i2*istep2;
249
float* outptr = outptr_orig + i0*ostep0 + i1*ostep1 + i2*ostep2;
250
251
for( int i3 = 0; i3 < n3; i3++ )
252
outptr[i3] = inptr[i3*istep3];
253
254
if( ++i2 >= n2 )
255
{
256
i2 = 0;
257
if( ++i1 >= n1 )
258
{
259
i1 = 0;
260
if( ++i0 >= n0 )
261
break;
262
}
263
}
264
}
265
}
266
};
267
268
#ifdef HAVE_OPENCL
269
bool forward_ocl(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
270
{
271
std::vector<UMat> inputs;
272
std::vector<UMat> outputs;
273
274
inps.getUMatVector(inputs);
275
outs.getUMatVector(outputs);
276
277
if (!_needsPermute)
278
return false;
279
280
bool use_half = (inps.depth() == CV_16S);
281
String opts = format("-DDtype=%s", use_half ? "half" : "float");
282
for (size_t i = 0; i < inputs.size(); i++)
283
{
284
ocl::Kernel kernel("permute", ocl::dnn::permute_oclsrc, opts);
285
286
kernel.set(0, (int)_count);
287
kernel.set(1, ocl::KernelArg::PtrReadOnly(inputs[i]));
288
kernel.set(2, ocl::KernelArg::PtrReadOnly(uorder));
289
kernel.set(3, ocl::KernelArg::PtrReadOnly(uold_stride));
290
kernel.set(4, ocl::KernelArg::PtrReadOnly(unew_stride));
291
kernel.set(5, (int)_numAxes);
292
kernel.set(6, ocl::KernelArg::PtrWriteOnly(outputs[i]));
293
294
if (!kernel.run(1, &_count, NULL, false))
295
return false;
296
}
297
298
return true;
299
}
300
#endif
301
302
void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
303
{
304
CV_TRACE_FUNCTION();
305
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
306
307
CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
308
forward_ocl(inputs_arr, outputs_arr, internals_arr))
309
310
if (inputs_arr.depth() == CV_16S)
311
{
312
forward_fallback(inputs_arr, outputs_arr, internals_arr);
313
return;
314
}
315
316
std::vector<Mat> inputs, outputs;
317
inputs_arr.getMatVector(inputs);
318
outputs_arr.getMatVector(outputs);
319
320
size_t k, ninputs = inputs.size();
321
if(!_needsPermute)
322
{
323
for (k = 0; k < ninputs; k++)
324
{
325
CV_Assert(outputs[k].total() == inputs[k].total());
326
if (outputs[k].data != inputs[k].data)
327
inputs[k].copyTo(outputs[k]);
328
}
329
}
330
else
331
{
332
size_t i, j, count = _count, numAxes = _numAxes;
333
const size_t* newStride = &_newStride[0];
334
const size_t* oldStride = &_oldStride[0];
335
const size_t* order = &_order[0];
336
337
for (k = 0; k < ninputs; k++)
338
{
339
const Mat& inp = inputs[k];
340
Mat& out = outputs[k];
341
342
CV_Assert(inp.dims == numAxes && inp.size == inputs[0].size);
343
CV_Assert(out.dims == numAxes && out.size == outputs[0].size);
344
345
CV_Assert(inp.isContinuous() && out.isContinuous());
346
CV_Assert(inp.type() == CV_32F && out.type() == CV_32F);
347
348
if( numAxes == 4 )
349
{
350
int nstripes = getNumThreads();
351
PermuteInvoker::run(inp, out, _order, nstripes);
352
}
353
else
354
{
355
const float *srcData = inp.ptr<float>();
356
float *dstData = out.ptr<float>();
357
358
for (i = 0; i < count; ++i)
359
{
360
size_t oldPosition = 0;
361
size_t newPosition = i;
362
363
for (j = 0; j < numAxes; ++j)
364
{
365
oldPosition += (newPosition / newStride[j]) * oldStride[order[j]];
366
newPosition %= newStride[j];
367
}
368
dstData[i] = srcData[oldPosition];
369
}
370
}
371
}
372
}
373
}
374
375
virtual Ptr<BackendNode> initVkCom(const std::vector<Ptr<BackendWrapper> > &input) CV_OVERRIDE
376
{
377
#ifdef HAVE_VULKAN
378
CV_Assert(!_order.empty());
379
std::shared_ptr<vkcom::OpBase> op(new vkcom::OpPermute(_order));
380
return Ptr<BackendNode>(new VkComBackendNode(input, op));
381
#endif // HAVE_VULKAN
382
return Ptr<BackendNode>();
383
}
384
385
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE
386
{
387
#ifdef HAVE_INF_ENGINE
388
InferenceEngine::LayerParams lp;
389
lp.name = name;
390
lp.type = "Permute";
391
lp.precision = InferenceEngine::Precision::FP32;
392
std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
393
394
CV_Assert(!_order.empty());
395
ieLayer->params["order"] = format("%zu", _order[0]);
396
for (int i = 1; i < _order.size(); ++i)
397
ieLayer->params["order"] += format(",%zu", _order[i]);
398
399
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
400
#endif // HAVE_INF_ENGINE
401
return Ptr<BackendNode>();
402
}
403
404
size_t _count;
405
std::vector<size_t> _order;
406
407
std::vector<int> _oldDimensionSize;
408
std::vector<int> _newDimensionSize;
409
410
std::vector<size_t> _oldStride;
411
std::vector<size_t> _newStride;
412
bool _needsPermute;
413
414
#ifdef HAVE_OPENCL
415
UMat uorder, uold_stride, unew_stride;
416
#endif
417
418
size_t _numAxes;
419
};
420
421
Ptr<PermuteLayer> PermuteLayer::create(const LayerParams &params)
422
{
423
return Ptr<PermuteLayer>(new PermuteLayerImpl(params));
424
}
425
426
}
427
}
428
429