1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
11 // For Open Source Computer Vision Library
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.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
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.
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.
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.
43 #include "../precomp.hpp"
44 #include "../op_inf_engine.hpp"
45 #include "layers_common.hpp"
46 #include <opencv2/dnn/shape_utils.hpp>
49 #include "opencl_kernels_dnn.hpp"
57 class SliceLayerImpl : public SliceLayer
60 SliceLayerImpl(const LayerParams& params)
62 setParamsFrom(params);
63 axis = params.get<int>("axis", 1);
64 num_split = params.get<int>("num_split", 0);
65 if (params.has("slice_point"))
67 CV_Assert(!params.has("begin") && !params.has("size") && !params.has("end"));
68 const DictValue &indicesValue = params.get("slice_point");
69 sliceRanges.resize(indicesValue.size() + 1,
70 std::vector<Range>(axis + 1, Range::all()));
72 for (int i = 0; i < indicesValue.size(); ++i)
74 sliceRanges[i][axis].start = prevSlice;
75 sliceRanges[i][axis].end = indicesValue.get<int>(i);
76 prevSlice = sliceRanges[i][axis].end;
78 sliceRanges.back()[axis].start = prevSlice;
80 else if (params.has("begin"))
82 CV_Assert(params.has("size") ^ params.has("end"));
83 const DictValue &begins = params.get("begin");
84 const DictValue &sizesOrEnds = params.has("size") ? params.get("size") : params.get("end");
85 CV_Assert(begins.size() == sizesOrEnds.size());
87 sliceRanges.resize(1);
88 sliceRanges[0].resize(begins.size(), Range::all());
89 for (int i = 0; i < begins.size(); ++i)
91 int start = begins.get<int>(i);
92 int sizeOrEnd = sizesOrEnds.get<int>(i); // It may be negative to reverse indexation.
93 CV_Assert(start >= 0);
95 sliceRanges[0][i].start = start;
96 if (params.has("size"))
99 CV_Assert(size == -1 || size > 0); // -1 value means range [start, axis_size).
100 sliceRanges[0][i].end = size > 0 ? (start + size) : -1; // We'll finalize a negative value later.
105 CV_Assert(end < 0 || end > start); // End index is excluded.
106 sliceRanges[0][i].end = end; // We'll finalize a negative value later.
112 virtual bool supportBackend(int backendId) CV_OVERRIDE
114 return backendId == DNN_BACKEND_OPENCV ||
115 (backendId == DNN_BACKEND_INFERENCE_ENGINE &&
116 #ifdef HAVE_INF_ENGINE
117 INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1) &&
119 sliceRanges.size() == 1 && sliceRanges[0].size() == 4);
122 bool getMemoryShapes(const std::vector<MatShape> &inputs,
123 const int requiredOutputs,
124 std::vector<MatShape> &outputs,
125 std::vector<MatShape> &internals) const CV_OVERRIDE
127 CV_Assert(inputs.size() == 1);
128 MatShape inpShape = inputs[0];
130 if (!sliceRanges.empty())
132 outputs.resize(sliceRanges.size(), inpShape);
133 for (int i = 0; i < outputs.size(); ++i)
135 CV_Assert(sliceRanges[i].size() <= inpShape.size());
136 for (int j = 0; j < sliceRanges[i].size(); ++j)
138 outputs[i][j] = clamp(sliceRanges[i][j], inpShape[j]).size();
142 else // Divide input blob on equal parts by axis.
144 CV_Assert(0 <= axis && axis < inpShape.size());
145 int splits = num_split ? num_split : requiredOutputs;
146 CV_Assert(splits > 0 && inpShape[axis] % splits == 0);
147 inpShape[axis] /= splits;
148 outputs.resize(splits, inpShape);
153 void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE
155 std::vector<Mat> inputs, outputs;
156 inputs_arr.getMatVector(inputs);
157 outputs_arr.getMatVector(outputs);
159 CV_Assert(inputs.size() == 1);
160 const MatSize& inpShape = inputs[0].size;
162 if (sliceRanges.empty())
164 // Divide input blob on equal parts by axis.
165 int outAxisSize = inpShape[axis] / outputs.size();
166 sliceRanges.resize(outputs.size(),
167 std::vector<Range>(axis + 1, Range::all()));
169 for (int i = 0; i < outputs.size(); ++i)
171 sliceRanges[i][axis].start = prevSlice;
172 sliceRanges[i][axis].end = sliceRanges[i][axis].start + outAxisSize;
173 prevSlice = sliceRanges[i][axis].end;
177 CV_Assert(outputs.size() == sliceRanges.size());
179 for (int i = 0; i < outputs.size(); ++i)
181 CV_Assert(sliceRanges[i].size() <= inpShape.dims());
182 // Fill the rest of ranges.
183 for (int j = sliceRanges[i].size(); j < inpShape.dims(); ++j)
185 sliceRanges[i].push_back(Range::all());
188 for (int j = 0; j < sliceRanges[i].size(); ++j)
190 sliceRanges[i][j] = clamp(sliceRanges[i][j], inpShape[j]);
196 bool forward_ocl(InputArrayOfArrays inputs_, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_)
198 std::vector<UMat> inputs;
199 std::vector<UMat> outputs;
201 bool use_half = (inputs_.depth() == CV_16S);
202 inputs_.getUMatVector(inputs);
203 outputs_.getUMatVector(outputs);
205 if (inputs[0].dims < 4 || (total(shape(outputs[0]), 0, 2) % 4 != 0) ||
206 (total(shape(outputs[0]), 2) % 4 != 0))
211 opts = "-DDtype=half -DDtype4=half4 -DDtype8=half8";
213 opts = "-DDtype=float -DDtype4=float4 -DDtype8=float8";
214 const UMat& inpMat = inputs[0];
215 for (size_t i = 0; i < outputs.size(); i++)
217 int groups = outputs[i].size[0];
218 int channels = outputs[i].size[1];
219 int rows = outputs[i].size[2];
220 int cols = outputs[i].size[3];
222 ocl::Kernel kernel("slice", ocl::dnn::slice_oclsrc, opts);
223 size_t local[] = { 128 };
224 size_t global[] = { (size_t)groups * channels / 4 * local[0] };
226 kernel.set(idx++, ocl::KernelArg::PtrReadOnly(inpMat));
227 kernel.set(idx++, (int)(inpMat.size[2] * inpMat.size[3]));
228 kernel.set(idx++, (int)(rows * cols));
229 kernel.set(idx++, (int)inpMat.size[3]);
230 kernel.set(idx++, (int)cols);
231 kernel.set(idx++, (int)sliceRanges[i][2].start);
232 kernel.set(idx++, (int)sliceRanges[i][3].start);
233 kernel.set(idx++, ocl::KernelArg::PtrWriteOnly(outputs[i]));
234 bool ret = kernel.run(1, global, local, false);
243 void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
246 CV_TRACE_ARG_VALUE(name, "name", name.c_str());
248 CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
249 forward_ocl(inputs_arr, outputs_arr, internals_arr))
251 std::vector<Mat> inputs, outputs;
252 inputs_arr.getMatVector(inputs);
253 outputs_arr.getMatVector(outputs);
255 const Mat& inpMat = inputs[0];
256 CV_Assert(outputs.size() == sliceRanges.size());
257 for (size_t i = 0; i < outputs.size(); i++)
259 inpMat(sliceRanges[i]).copyTo(outputs[i]);
263 #ifdef HAVE_INF_ENGINE
264 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
265 virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE
267 CV_Assert_N(sliceRanges.size() == 1, inputs.size() <= 2);
269 std::vector<size_t> axes, offsets, dims;
271 int numDims = sliceRanges[0].size();
272 if (preferableTarget == DNN_TARGET_MYRIAD)
284 for (int i = from; i != to; i += step)
287 offsets.push_back(sliceRanges[0][i].start);
288 dims.push_back(sliceRanges[0][i].size());
291 InferenceEngine::Builder::Layer ieLayer(name);
292 ieLayer.setName(name);
293 ieLayer.setType("Crop");
294 ieLayer.getParameters()["axis"] = axes;
295 ieLayer.getParameters()["dim"] = dims;
296 ieLayer.getParameters()["offset"] = offsets;
297 ieLayer.setInputPorts(std::vector<InferenceEngine::Port>(2));
298 ieLayer.setOutputPorts(std::vector<InferenceEngine::Port>(1));
300 if (inputs.size() != 2)
302 std::vector<size_t> outShape(numDims);
303 for (int i = 0; i < numDims; ++i)
304 outShape[i] = sliceRanges[0][i].size();
306 ieLayer.getInputPorts()[1].setParameter("type", "weights");
308 auto shapeSource = InferenceEngine::make_shared_blob<float>({
309 InferenceEngine::Precision::FP32, outShape,
310 InferenceEngine::Layout::ANY
312 shapeSource->allocate();
313 addConstantData("weights", shapeSource, ieLayer);
315 return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
321 class CropLayerImpl CV_FINAL : public SliceLayerImpl
324 CropLayerImpl(const LayerParams& params) : SliceLayerImpl(LayerParams())
326 setParamsFrom(params);
327 axis = params.get<int>("axis", 2);
328 const DictValue *paramOffset = params.ptr("offset");
332 for (int i = 0; i < paramOffset->size(); i++)
333 offset.push_back(paramOffset->get<int>(i));
337 bool getMemoryShapes(const std::vector<MatShape> &inputs,
338 const int requiredOutputs,
339 std::vector<MatShape> &outputs,
340 std::vector<MatShape> &internals) const CV_OVERRIDE
342 CV_Assert(inputs.size() == 2);
344 MatShape dstShape = inputs[0];
345 int start = clamp(axis, dstShape);
346 for (int i = start; i < dstShape.size(); i++)
348 dstShape[i] = inputs[1][i];
350 outputs.resize(1, dstShape);
354 void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
356 std::vector<Mat> inputs;
357 inputs_arr.getMatVector(inputs);
358 CV_Assert(2 == inputs.size());
360 const Mat &inpBlob = inputs[0];
361 const Mat &inpSzBlob = inputs[1];
363 int dims = inpBlob.dims;
364 int start_axis = clamp(axis, dims);
366 std::vector<int> offset_final(dims, 0);
367 if (offset.size() == 1)
369 for (int i = start_axis; i < dims; i++)
370 offset_final[i] = offset[0];
372 else if (offset.size() > 1)
374 if ((int)offset.size() != dims - start_axis)
375 CV_Error(Error::StsBadArg, "number of offset values specified must be "
376 "equal to the number of dimensions following axis.");
378 for (int i = start_axis; i < dims; i++)
379 offset_final[i] = offset[i - start_axis];
382 sliceRanges.resize(1);
383 sliceRanges[0].resize(dims);
384 for (int i = 0; i < start_axis; i++)
386 sliceRanges[0][i] = Range(0, inpBlob.size[i]);
388 for (int i = start_axis; i < dims; i++)
390 if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size[i] > inpBlob.size[i])
391 CV_Error(Error::StsBadArg, "invalid crop parameters or blob sizes");
393 sliceRanges[0][i] = Range(offset_final[i], offset_final[i] + inpSzBlob.size[i]);
398 std::vector<int> offset;
401 Ptr<SliceLayer> SliceLayer::create(const LayerParams& params)
403 return Ptr<SliceLayer>(new SliceLayerImpl(params));
406 Ptr<Layer> CropLayer::create(const LayerParams& params)
408 return Ptr<Layer>(new CropLayerImpl(params));