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_cuda.hpp"
45 #include "../op_inf_engine.hpp"
46 #include "layers_common.hpp"
47 #include <opencv2/dnn/shape_utils.hpp>
50 #include "opencl_kernels_dnn.hpp"
54 #include "../cuda4dnn/primitives/slice.hpp"
55 using namespace cv::dnn::cuda4dnn;
63 class SliceLayerImpl : public SliceLayer
66 SliceLayerImpl(const LayerParams& params)
68 setParamsFrom(params);
69 axis = params.get<int>("axis", 1);
70 num_split = params.get<int>("num_split", 0);
71 if (params.has("slice_point"))
73 CV_Assert(!params.has("begin") && !params.has("size") && !params.has("end"));
74 const DictValue &indicesValue = params.get("slice_point");
75 sliceRanges.resize(indicesValue.size() + 1,
76 std::vector<Range>(axis + 1, Range::all()));
78 for (int i = 0; i < indicesValue.size(); ++i)
80 sliceRanges[i][axis].start = prevSlice;
81 sliceRanges[i][axis].end = indicesValue.get<int>(i);
82 prevSlice = sliceRanges[i][axis].end;
84 sliceRanges.back()[axis].start = prevSlice;
86 else if (params.has("begin"))
88 CV_Assert(params.has("size") ^ params.has("end"));
89 const DictValue &begins = params.get("begin");
90 const DictValue &sizesOrEnds = params.has("size") ? params.get("size") : params.get("end");
91 CV_Assert(begins.size() == sizesOrEnds.size());
93 sliceRanges.resize(1);
94 sliceRanges[0].resize(begins.size(), Range::all());
95 for (int i = 0; i < begins.size(); ++i)
97 int start = begins.get<int>(i);
98 int sizeOrEnd = sizesOrEnds.get<int>(i); // It may be negative to reverse indexation.
99 CV_Assert(start >= 0);
101 sliceRanges[0][i].start = start;
102 if (params.has("size"))
104 int size = sizeOrEnd;
105 CV_Assert(size == -1 || size > 0); // -1 value means range [start, axis_size).
106 sliceRanges[0][i].end = size > 0 ? (start + size) : -1; // We'll finalize a negative value later.
111 CV_Assert(end < 0 || end > start); // End index is excluded.
112 sliceRanges[0][i].end = end; // We'll finalize a negative value later.
118 virtual bool supportBackend(int backendId) CV_OVERRIDE
120 return backendId == DNN_BACKEND_OPENCV ||
121 backendId == DNN_BACKEND_CUDA ||
122 (backendId == DNN_BACKEND_INFERENCE_ENGINE &&
123 #ifdef HAVE_INF_ENGINE
124 INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1) &&
126 sliceRanges.size() == 1 && sliceRanges[0].size() == 4);
129 bool getMemoryShapes(const std::vector<MatShape> &inputs,
130 const int requiredOutputs,
131 std::vector<MatShape> &outputs,
132 std::vector<MatShape> &internals) const CV_OVERRIDE
134 CV_Assert(inputs.size() == 1);
135 MatShape inpShape = inputs[0];
137 if (!sliceRanges.empty())
139 outputs.resize(sliceRanges.size(), inpShape);
140 for (int i = 0; i < outputs.size(); ++i)
142 CV_Assert(sliceRanges[i].size() <= inpShape.size());
143 for (int j = 0; j < sliceRanges[i].size(); ++j)
145 outputs[i][j] = clamp(sliceRanges[i][j], inpShape[j]).size();
149 else // Divide input blob on equal parts by axis.
151 CV_Assert(0 <= axis && axis < inpShape.size());
152 int splits = num_split ? num_split : requiredOutputs;
153 CV_Assert(splits > 0 && inpShape[axis] % splits == 0);
154 inpShape[axis] /= splits;
155 outputs.resize(splits, inpShape);
160 void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE
162 std::vector<Mat> inputs, outputs;
163 inputs_arr.getMatVector(inputs);
164 outputs_arr.getMatVector(outputs);
166 CV_Assert(inputs.size() == 1);
167 const MatSize& inpShape = inputs[0].size;
169 if (sliceRanges.empty())
171 // Divide input blob on equal parts by axis.
172 int outAxisSize = inpShape[axis] / outputs.size();
173 sliceRanges.resize(outputs.size(),
174 std::vector<Range>(axis + 1, Range::all()));
176 for (int i = 0; i < outputs.size(); ++i)
178 sliceRanges[i][axis].start = prevSlice;
179 sliceRanges[i][axis].end = sliceRanges[i][axis].start + outAxisSize;
180 prevSlice = sliceRanges[i][axis].end;
184 CV_Assert(outputs.size() == sliceRanges.size());
186 for (int i = 0; i < outputs.size(); ++i)
188 CV_Assert(sliceRanges[i].size() <= inpShape.dims());
189 // Fill the rest of ranges.
190 for (int j = sliceRanges[i].size(); j < inpShape.dims(); ++j)
192 sliceRanges[i].push_back(Range::all());
195 for (int j = 0; j < sliceRanges[i].size(); ++j)
197 sliceRanges[i][j] = clamp(sliceRanges[i][j], inpShape[j]);
203 bool forward_ocl(InputArrayOfArrays inputs_, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_)
205 std::vector<UMat> inputs;
206 std::vector<UMat> outputs;
208 bool use_half = (inputs_.depth() == CV_16S);
209 inputs_.getUMatVector(inputs);
210 outputs_.getUMatVector(outputs);
212 if (inputs[0].dims < 4 || (total(shape(outputs[0]), 0, 2) % 4 != 0) ||
213 (total(shape(outputs[0]), 2) % 4 != 0))
218 opts = "-DDtype=half -DDtype4=half4 -DDtype8=half8";
220 opts = "-DDtype=float -DDtype4=float4 -DDtype8=float8";
221 const UMat& inpMat = inputs[0];
222 for (size_t i = 0; i < outputs.size(); i++)
224 int groups = outputs[i].size[0];
225 int channels = outputs[i].size[1];
226 int rows = outputs[i].size[2];
227 int cols = outputs[i].size[3];
229 ocl::Kernel kernel("slice", ocl::dnn::slice_oclsrc, opts);
230 size_t local[] = { 128 };
231 size_t global[] = { (size_t)groups * channels / 4 * local[0] };
233 kernel.set(idx++, ocl::KernelArg::PtrReadOnly(inpMat));
234 kernel.set(idx++, (int)(inpMat.size[2] * inpMat.size[3]));
235 kernel.set(idx++, (int)(rows * cols));
236 kernel.set(idx++, (int)inpMat.size[3]);
237 kernel.set(idx++, (int)cols);
238 kernel.set(idx++, (int)sliceRanges[i][2].start);
239 kernel.set(idx++, (int)sliceRanges[i][3].start);
240 kernel.set(idx++, ocl::KernelArg::PtrWriteOnly(outputs[i]));
241 bool ret = kernel.run(1, global, local, false);
250 void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
253 CV_TRACE_ARG_VALUE(name, "name", name.c_str());
255 CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
256 forward_ocl(inputs_arr, outputs_arr, internals_arr))
258 std::vector<Mat> inputs, outputs;
259 inputs_arr.getMatVector(inputs);
260 outputs_arr.getMatVector(outputs);
262 const Mat& inpMat = inputs[0];
263 CV_Assert(outputs.size() == sliceRanges.size());
264 for (size_t i = 0; i < outputs.size(); i++)
266 inpMat(sliceRanges[i]).copyTo(outputs[i]);
271 Ptr<BackendNode> initCUDA(
273 const std::vector<Ptr<BackendWrapper>>& inputs,
274 const std::vector<Ptr<BackendWrapper>>& outputs
277 auto context = reinterpret_cast<csl::CSLContext*>(context_);
279 std::vector<std::vector<std::size_t>> offsets;
280 for (const auto& ranges : sliceRanges)
282 std::vector<std::size_t> offsets_i;
283 for (const auto& range : ranges)
284 offsets_i.push_back(range.start);
285 offsets.push_back(std::move(offsets_i));
288 return make_cuda_node<cuda4dnn::SliceOp>(preferableTarget, std::move(context->stream), std::move(offsets));
292 #ifdef HAVE_INF_ENGINE
293 #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1)
294 virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE
296 CV_Assert_N(sliceRanges.size() == 1, inputs.size() <= 2);
298 std::vector<size_t> axes, offsets, dims;
300 int numDims = sliceRanges[0].size();
301 if (preferableTarget == DNN_TARGET_MYRIAD)
313 for (int i = from; i != to; i += step)
316 offsets.push_back(sliceRanges[0][i].start);
317 dims.push_back(sliceRanges[0][i].size());
320 InferenceEngine::Builder::Layer ieLayer(name);
321 ieLayer.setName(name);
322 ieLayer.setType("Crop");
323 ieLayer.getParameters()["axis"] = axes;
324 ieLayer.getParameters()["dim"] = dims;
325 ieLayer.getParameters()["offset"] = offsets;
326 ieLayer.setInputPorts(std::vector<InferenceEngine::Port>(2));
327 ieLayer.setOutputPorts(std::vector<InferenceEngine::Port>(1));
329 if (inputs.size() != 2)
331 std::vector<size_t> outShape(numDims);
332 for (int i = 0; i < numDims; ++i)
333 outShape[i] = sliceRanges[0][i].size();
335 ieLayer.getInputPorts()[1].setParameter("type", "weights");
337 auto shapeSource = InferenceEngine::make_shared_blob<float>({
338 InferenceEngine::Precision::FP32, outShape,
339 InferenceEngine::Layout::ANY
341 shapeSource->allocate();
342 addConstantData("weights", shapeSource, ieLayer);
344 return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
350 class CropLayerImpl CV_FINAL : public SliceLayerImpl
353 CropLayerImpl(const LayerParams& params) : SliceLayerImpl(LayerParams())
355 setParamsFrom(params);
356 axis = params.get<int>("axis", 2);
357 const DictValue *paramOffset = params.ptr("offset");
361 for (int i = 0; i < paramOffset->size(); i++)
362 offset.push_back(paramOffset->get<int>(i));
366 bool getMemoryShapes(const std::vector<MatShape> &inputs,
367 const int requiredOutputs,
368 std::vector<MatShape> &outputs,
369 std::vector<MatShape> &internals) const CV_OVERRIDE
371 CV_Assert(inputs.size() == 2);
373 MatShape dstShape = inputs[0];
374 int start = clamp(axis, dstShape);
375 for (int i = start; i < dstShape.size(); i++)
377 dstShape[i] = inputs[1][i];
379 outputs.resize(1, dstShape);
383 void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
385 std::vector<Mat> inputs;
386 inputs_arr.getMatVector(inputs);
387 CV_Assert(2 == inputs.size());
389 const Mat &inpBlob = inputs[0];
390 const Mat &inpSzBlob = inputs[1];
392 int dims = inpBlob.dims;
393 int start_axis = clamp(axis, dims);
395 std::vector<int> offset_final(dims, 0);
396 if (offset.size() == 1)
398 for (int i = start_axis; i < dims; i++)
399 offset_final[i] = offset[0];
401 else if (offset.size() > 1)
403 if ((int)offset.size() != dims - start_axis)
404 CV_Error(Error::StsBadArg, "number of offset values specified must be "
405 "equal to the number of dimensions following axis.");
407 for (int i = start_axis; i < dims; i++)
408 offset_final[i] = offset[i - start_axis];
411 sliceRanges.resize(1);
412 sliceRanges[0].resize(dims);
413 for (int i = 0; i < start_axis; i++)
415 sliceRanges[0][i] = Range(0, inpBlob.size[i]);
417 for (int i = start_axis; i < dims; i++)
419 if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size[i] > inpBlob.size[i])
420 CV_Error(Error::StsBadArg, "invalid crop parameters or blob sizes");
422 sliceRanges[0][i] = Range(offset_final[i], offset_final[i] + inpSzBlob.size[i]);
427 std::vector<int> offset;
430 Ptr<SliceLayer> SliceLayer::create(const LayerParams& params)
432 return Ptr<SliceLayer>(new SliceLayerImpl(params));
435 Ptr<Layer> CropLayer::create(const LayerParams& params)
437 return Ptr<Layer>(new CropLayerImpl(params));