diff --git a/inference-engine/src/cldnn_engine/cldnn_engine.cpp b/inference-engine/src/cldnn_engine/cldnn_engine.cpp index 80254dca3c0468..31b51aed9a913a 100644 --- a/inference-engine/src/cldnn_engine/cldnn_engine.cpp +++ b/inference-engine/src/cldnn_engine/cldnn_engine.cpp @@ -83,7 +83,7 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneNetwork(const InferenceEngin ::ngraph::op::GenericIE::DisableReshape noReshape(nGraphFunc); // Note: instead of running all Conversion Transformations you can make up your own transformation pipeline - ngraph::pass::CommonOptimizations().run_on_function(nGraphFunc); + ngraph::pass::CommonOptimizations(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet3ToOpSet2(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet2ToOpSet1(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet1ToLegacy(transformations_callback).run_on_function(nGraphFunc); diff --git a/inference-engine/src/legacy_api/src/ie_layer_validators.cpp b/inference-engine/src/legacy_api/src/ie_layer_validators.cpp index c3ecac9adfa168..ba833d329a413d 100644 --- a/inference-engine/src/legacy_api/src/ie_layer_validators.cpp +++ b/inference-engine/src/legacy_api/src/ie_layer_validators.cpp @@ -1371,9 +1371,9 @@ void DepthToSpaceValidator::checkShapes(const CNNLayer* layer, const vectorblock_size == 0) THROW_IE_EXCEPTION << layer->name << " Incorrect block_size parameter is zero!"; - if (inShapes[0][inShapes[0].size() - 3] % (casted->block_size * casted->block_size)) - THROW_IE_EXCEPTION << layer->name - << " block_size parameter is incompatible with input tensor Color dimension size!"; + size_t numSpatialDims = inShapes[0].size() - 2; + if (inShapes[0][1] % static_cast(std::pow(casted->block_size, numSpatialDims))) + THROW_IE_EXCEPTION << layer->name << " block_size parameter is incompatible with input tensor Color dimension size!"; } SpaceToDepthValidator::SpaceToDepthValidator(const std::string& _type): LayerValidator(_type) {} diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index 95c7a38a59c100..a2af567b98db77 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -82,6 +82,16 @@ Engine::LoadExeNetworkImpl(const InferenceEngine::ICNNNetwork &network, const st if (clonedNetwork->getFunction()) { const auto transformations_callback = [](const std::shared_ptr &node) -> bool { + // DepthToSpace node implementation supports only equal input/output tensors with rank <= 5 + if (auto dtsOp = std::dynamic_pointer_cast(node)) { + return dtsOp->input_value(0).get_shape().size() <= 5lu && dtsOp->input_value(0).get_shape().size() == dtsOp->get_output_shape(0).size(); + } + + // SpaceToDepth node implementation supports only equal input/output tensors with rank <= 5 + if (auto stdOp = std::dynamic_pointer_cast(node)) { + return stdOp->input_value(0).get_shape().size() <= 5lu && stdOp->input_value(0).get_shape().size() == stdOp->get_output_shape(0).size(); + } + return std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || @@ -92,7 +102,7 @@ Engine::LoadExeNetworkImpl(const InferenceEngine::ICNNNetwork &network, const st ::ngraph::op::GenericIE::DisableReshape noReshape(nGraphFunc); // Note: instead of running all Conversion Transformations you can make up your own transformation pipeline - ngraph::pass::CommonOptimizations().run_on_function(nGraphFunc); + ngraph::pass::CommonOptimizations(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet3ToOpSet2(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet2ToOpSet1(transformations_callback).run_on_function(nGraphFunc); ngraph::pass::ConvertOpSet1ToLegacy(transformations_callback).run_on_function(nGraphFunc); diff --git a/inference-engine/src/mkldnn_plugin/nodes/depth_to_space.cpp b/inference-engine/src/mkldnn_plugin/nodes/depth_to_space.cpp index 69d9024029f0ea..ee6b2d6a4a6086 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/depth_to_space.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/depth_to_space.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "ie_parallel.hpp" namespace InferenceEngine { @@ -15,106 +16,202 @@ namespace Extensions { namespace Cpu { class DepthToSpaceImpl: public ExtLayerBase { -#define CNTR_SIZE 5 + enum class DepthToSpaceMode { + BLOCKS_FIRST, + DEPTH_FIRST + }; public: explicit DepthToSpaceImpl(const CNNLayer* layer) { try { if (layer->insData.empty() || layer->outData.empty()) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output edges!"; - - SizeVector src_dims = layer->insData[0].lock()->getTensorDesc().getDims(); - if (src_dims.size() < 3) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of input dimensions!"; - if (layer->insData[0].lock()->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect input precision. Only F32 is supported!"; - - SizeVector dst_dims = layer->outData[0]->getTensorDesc().getDims(); - if (dst_dims.size() < 2) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of output dimensions!"; - if (layer->outData[0]->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect output precision. Only F32 is supported!"; - - size_t block_size = layer->GetParamAsUInt("block_size", 1); - if (block_size == 0) - THROW_IE_EXCEPTION << layer->name << " Incorrect block_size parameter is zero!"; - - if (src_dims[src_dims.size() - 3] % (block_size * block_size)) - THROW_IE_EXCEPTION << layer->name << " block_size parameter is incompatible with input tensor Color dimension size!"; - - if (dst_dims.size() > 2 && src_dims[src_dims.size() - 3] != (dst_dims[dst_dims.size() - 3] * block_size * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Color dimension is incompatible with block_size!"; - - if (dst_dims[dst_dims.size() - 2] != (src_dims[src_dims.size() - 2] * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Height dimension is incompatible with block_size!"; - - if (dst_dims[dst_dims.size() - 1] != (src_dims[src_dims.size() - 1] * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Width dimension is incompatible with block_size!"; - - own_dims[0] = 1; - for (size_t i = 0; i < (src_dims.size() - 3); i++) - own_dims[0] *= src_dims[i]; - own_dims[1] = src_dims[src_dims.size() - 2]; - own_dims[2] = src_dims[src_dims.size() - 3] / block_size; - own_dims[3] = src_dims[src_dims.size() - 1]; - own_dims[4] = block_size; - - size_t C = src_dims[src_dims.size() - 2] * src_dims[src_dims.size() - 1]; - ownStrides[0] = src_dims[src_dims.size() - 3] * C; - ownStrides[1] = src_dims[src_dims.size() - 1]; - ownStrides[2] = block_size * C; - ownStrides[3] = 1; - ownStrides[4] = C; - work_amount_dst = ownStrides[0] * own_dims[0]; - - addConfig(layer, { DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) }); + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' has incorrect number of input/output edges"; + + inDims = layer->insData[0].lock()->getTensorDesc().getDims(); + if (inDims.size() < 3) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' has incorrect number of input dimensions"; + + if (inDims.size() > 5) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' doesn't support dimensions with rank greater than 5"; + + SizeVector outDims = layer->outData[0]->getTensorDesc().getDims(); + if (inDims.size() != outDims.size()) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' has incorrect number of input/output dimensions"; + + std::string modeString = layer->GetParamAsString("mode"); + if (modeString == "blocks_first") { + mode = DepthToSpaceMode::BLOCKS_FIRST; + } else if (modeString == "depth_first") { + mode = DepthToSpaceMode::DEPTH_FIRST; + } else { + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' doesn't support mode: " << modeString; + } + + blockSize = layer->GetParamAsUInt("block_size", 1); + if (blockSize == 0) + THROW_IE_EXCEPTION << layer->name << " Incorrect blockSize parameter is zero!"; + + size_t numSpatialDims = inDims.size() - 2; + blockStep = static_cast(std::pow(blockSize, numSpatialDims)); + if (inDims[1] % blockStep) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << + "' has block_size parameter which is incompatible with input tensor channels dimension size"; + + if (inDims[1] / blockStep != outDims[1]) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << " has incompatible input/output channels"; + + for (int i = 0; i < numSpatialDims; i++) { + if (inDims[i + 2] != outDims[i + 2] / blockSize) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << " has incompatible spatial dims"; + } + + auto computePrc = layer->insData[0].lock()->getTensorDesc().getPrecision(); + const std::set supported_precision_sizes = {1, 2, 4, 8}; + if (supported_precision_sizes.find(computePrc.size()) == supported_precision_sizes.end()) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << " doesn't support precision: " << computePrc.name(); + + + if (inDims.size() == 4 || inDims.size() == 5) { + LayerConfig config; + DataConfig inConfig; + inConfig.desc = TensorDesc(computePrc, inDims, inDims.size() == 4 ? NHWC : NDHWC); + config.inConfs.push_back(inConfig); + + DataConfig outConfig; + outConfig.desc = TensorDesc(computePrc, outDims, outDims.size() == 4 ? NHWC : NDHWC); + config.outConfs.push_back(outConfig); + + config.dynBatchSupport = false; + confs.push_back(config); + } + + LayerConfig config; + DataConfig inConfig; + inConfig.desc = TensorDesc(computePrc, inDims, InferenceEngine::TensorDesc::getLayoutByDims(inDims)); + config.inConfs.push_back(inConfig); + + DataConfig outConfig; + outConfig.desc = TensorDesc(computePrc, outDims, InferenceEngine::TensorDesc::getLayoutByDims(outDims)); + config.outConfs.push_back(outConfig); + + config.dynBatchSupport = false; + confs.push_back(config); } catch (InferenceEngine::details::InferenceEngineException &ex) { errorMsg = ex.what(); } } StatusCode execute(std::vector& inputs, std::vector& outputs, ResponseDesc *resp) noexcept override { - const float *src_data = inputs[0]->cbuffer().as() + - inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); - float* dst_data = outputs[0]->cbuffer().as() + - outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); - - // Parallel - parallel_nt(0, [&](const int ithr, const int nthr) { - size_t start = 0, end = 0, src_idx = 0; - size_t counters[CNTR_SIZE] = { 0 }; - splitter(work_amount_dst, nthr, ithr, start, end); - for (int j = CNTR_SIZE - 1, i = start; j >= 0; j--) { - counters[j] = i % own_dims[j]; - src_idx += counters[j] * ownStrides[j]; - i /= own_dims[j]; - } - - for (size_t iwork = start, i = 1; iwork < end; ++iwork) { - dst_data[iwork] = src_data[src_idx]; - for (int j = CNTR_SIZE - 1; j >= 0; j--) { - counters[j]++; - if (counters[j] < own_dims[j]) { - src_idx += ownStrides[j]; - break; - } else { - counters[j] = i = 0; - } - } - if (!i) { - for (src_idx = 0; i < CNTR_SIZE; ++i) - src_idx += counters[i] * ownStrides[i]; + switch (inputs[0]->getTensorDesc().getPrecision().size()) { + case 1: depthToSpaceKernel::value_type>(inputs, outputs); break; + case 2: depthToSpaceKernel::value_type>(inputs, outputs); break; + case 4: depthToSpaceKernel::value_type>(inputs, outputs); break; + case 8: depthToSpaceKernel::value_type>(inputs, outputs); break; + default: { + if (resp) { + std::string errorMsg = "DepthToSpace layer with name does not support precision '" + + std::string(inputs[0]->getTensorDesc().getPrecision().name()) + "'"; + errorMsg.copy(resp->msg, sizeof(resp->msg) - 1); + + return GENERAL_ERROR; } } - }); + } return OK; } private: - size_t work_amount_dst; - size_t own_dims[CNTR_SIZE]; - size_t ownStrides[CNTR_SIZE]; + std::vector getShape5D(const SizeVector& shape) { + std::vector shape5D(5, 1); + for (int i = 0; i < shape.size(); i++) { + shape5D[i] = shape[i]; + } + return shape5D; + } + + std::vector getBlock3D(const SizeVector& shape, const SizeVector& shape5D) { + std::vector block3D(3, 1); + for (int i = 0; i < shape.size() - 2; i++) { + block3D[i] = blockSize; + } + return block3D; + } + + template + void depthToSpaceKernel(std::vector& inputs, std::vector& outputs) { + const T *src_data = inputs[0]->cbuffer().as() + inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + T* dst_data = outputs[0]->buffer().as() + outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + + auto shape5D = getShape5D(inDims); + auto block3D = getBlock3D(inDims, shape5D); + + size_t spatialStep = shape5D[2] * shape5D[3] * shape5D[4]; + size_t batchStep = shape5D[1] * spatialStep; + + size_t srcChannels = shape5D[1]; + size_t dstChannels = srcChannels / blockStep; + + size_t blockShift = mode == DepthToSpaceMode::BLOCKS_FIRST ? (dstChannels) : 1; + size_t channelShift = mode == DepthToSpaceMode::BLOCKS_FIRST ? 1 : blockStep; + + if (inputs[0]->getTensorDesc().getLayout() == NHWC || inputs[0]->getTensorDesc().getLayout() == NDHWC) { + parallel_for2d(shape5D[0], shape5D[2], [&](size_t i0, size_t i2) { + size_t srcIdx1 = i0 * batchStep; + size_t dstIdx1 = i0 * batchStep; + for (size_t b2 = 0; b2 < block3D[0]; b2++) { + size_t srcIdx2 = srcIdx1 + i2 * shape5D[3] * shape5D[4] * srcChannels + b2 * block3D[1] * block3D[2] * blockShift; + size_t dstIdx2 = dstIdx1 + (i2 * block3D[0] + b2) * shape5D[3] * block3D[1] * shape5D[4] * block3D[2] * dstChannels; + for (size_t i3 = 0; i3 < shape5D[3]; i3++) { + for (size_t b3 = 0; b3 < block3D[1]; b3++) { + size_t srcIdx3 = srcIdx2 + i3 * shape5D[4] * srcChannels + b3 * block3D[2] * blockShift; + size_t dstIdx3 = dstIdx2 + (i3 * block3D[1] + b3) * shape5D[4] * block3D[2] * dstChannels; + for (size_t i4 = 0; i4 < shape5D[4]; i4++) { + for (size_t b4 = 0; b4 < block3D[2]; b4++) { + size_t srcIdx4 = srcIdx3 + i4 * srcChannels + b4 * blockShift; + size_t dstIdx4 = dstIdx3 + (i4 * block3D[2] + b4) * dstChannels; + for (size_t i1 = 0; i1 < dstChannels; i1++) { + size_t srcIdx5 = srcIdx4 + i1 * channelShift; + size_t dstIdx5 = dstIdx4 + i1; + dst_data[dstIdx5] = src_data[srcIdx5]; + } + } + } + } + } + } + }); + } else { + parallel_for2d(shape5D[0], dstChannels, [&](size_t i0, size_t i1) { + size_t srcIdx1 = i0 * batchStep + i1 * channelShift * spatialStep; + size_t dstIdx1 = i0 * batchStep + i1 * blockStep * spatialStep; + for (size_t i2 = 0; i2 < shape5D[2]; i2++) { + for (size_t b2 = 0; b2 < block3D[0]; b2++) { + size_t srcIdx2 = srcIdx1 + i2 * shape5D[3] * shape5D[4] + b2 * block3D[1] * block3D[2] * blockShift * spatialStep; + size_t dstIdx2 = dstIdx1 + (i2 * block3D[0] + b2) * shape5D[3] * block3D[1] * shape5D[4] * block3D[2]; + for (size_t i3 = 0; i3 < shape5D[3]; i3++) { + for (size_t b3 = 0; b3 < block3D[1]; b3++) { + size_t srcIdx3 = srcIdx2 + i3 * shape5D[4] + b3 * block3D[2] * blockShift * spatialStep; + size_t dstIdx3 = dstIdx2 + (i3 * block3D[1] + b3) * shape5D[4] * block3D[2]; + for (size_t i4 = 0; i4 < shape5D[4]; i4++) { + for (size_t b4 = 0; b4 < block3D[2]; b4++) { + size_t srcIdx4 = srcIdx3 + i4 + b4 * blockShift * spatialStep; + size_t dstIdx4 = dstIdx3 + i4 * block3D[2] + b4; + dst_data[dstIdx4] = src_data[srcIdx4]; + } + } + } + } + } + } + }); + } + } + + DepthToSpaceMode mode; + SizeVector inDims; + size_t blockSize; + size_t blockStep; }; REG_FACTORY_FOR(DepthToSpaceImpl, DepthToSpace); diff --git a/inference-engine/src/mkldnn_plugin/nodes/space_to_depth.cpp b/inference-engine/src/mkldnn_plugin/nodes/space_to_depth.cpp index 911dc69370c8b7..6014063305e7bd 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/space_to_depth.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/space_to_depth.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "ie_parallel.hpp" namespace InferenceEngine { @@ -15,107 +16,202 @@ namespace Extensions { namespace Cpu { class SpaceToDepthImpl: public ExtLayerBase { -#define CNTR_SIZE 5 + enum class SpaceToDepthMode { + BLOCKS_FIRST, + DEPTH_FIRST + }; public: explicit SpaceToDepthImpl(const CNNLayer* layer) { try { if (layer->insData.empty() || layer->outData.empty()) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output edges!"; - - SizeVector src_dims = layer->insData[0].lock()->getTensorDesc().getDims(); - if (src_dims.size() < 2) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of input dimensions!"; - if (layer->insData[0].lock()->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect input precision. Only F32 is supported!"; - - SizeVector dst_dims = layer->outData[0]->getTensorDesc().getDims(); - if (dst_dims.size() < 3) - THROW_IE_EXCEPTION << layer->name << " Incorrect number of output dimensions!"; - if (layer->outData[0]->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect output precision. Only F32 is supported!"; - - size_t block_size = layer->GetParamAsUInt("block_size", 1); - if (block_size == 0) - THROW_IE_EXCEPTION << layer->name << " Incorrect block_size parameter is zero!"; - - if (dst_dims[dst_dims.size() - 3] % (block_size * block_size)) - THROW_IE_EXCEPTION << layer->name << " block_size parameter is incompatible with input tensor Color dimension size!"; - - if (src_dims.size() > 2 && dst_dims[dst_dims.size() - 3] != (src_dims[src_dims.size() - 3] * block_size * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Color dimension is incompatible with block_size!"; - - if (src_dims[src_dims.size() - 2] != (dst_dims[dst_dims.size() - 2] * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Height dimension is incompatible with block_size!"; - - if (src_dims[src_dims.size() - 1] != (dst_dims[dst_dims.size() - 1] * block_size)) - THROW_IE_EXCEPTION << layer->name << " Input/Output tensor Width dimension is incompatible with block_size!"; - - own_dims[0] = 1; - for (size_t i = 0; i < (dst_dims.size() - 3); i++) - own_dims[0] *= dst_dims[i]; - own_dims[1] = dst_dims[dst_dims.size() - 2]; - own_dims[2] = dst_dims[dst_dims.size() - 3] / block_size; - own_dims[3] = dst_dims[dst_dims.size() - 1]; - own_dims[4] = block_size; - - size_t C = dst_dims[dst_dims.size() - 2] * dst_dims[dst_dims.size() - 1]; - ownStrides[0] = dst_dims[dst_dims.size() - 3] * C; - ownStrides[1] = dst_dims[dst_dims.size() - 1]; - ownStrides[2] = block_size * C; - ownStrides[3] = 1; - ownStrides[4] = C; - work_amount_dst = ownStrides[0] * own_dims[0]; - - addConfig(layer, { DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) }); + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << "' has incorrect number of input/output edges"; + + SizeVector inDims = layer->insData[0].lock()->getTensorDesc().getDims(); + if (inDims.size() < 3) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << "' has incorrect number of input dimensions"; + + if (inDims.size() > 5) + THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' doesn't support dimensions with rank greater than 5"; + + outDims = layer->outData[0]->getTensorDesc().getDims(); + if (inDims.size() != outDims.size()) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << "' has incorrect number of input/output dimensions"; + + std::string modeString = layer->GetParamAsString("mode"); + if (modeString == "blocks_first") { + mode = SpaceToDepthMode::BLOCKS_FIRST; + } else if (modeString == "depth_first") { + mode = SpaceToDepthMode::DEPTH_FIRST; + } else { + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << "' doesn't support mode: " << modeString; + } + + blockSize = layer->GetParamAsUInt("block_size", 1); + if (blockSize == 0) + THROW_IE_EXCEPTION << layer->name << " Incorrect blockSize parameter is zero!"; + + size_t numSpatialDims = inDims.size() - 2; + blockStep = static_cast(std::pow(blockSize, numSpatialDims)); + if (outDims[1] % blockStep) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << + "' has block_size parameter which is incompatible with input tensor channels dimension size"; + + if (inDims[1] != outDims[1] / blockStep) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << " has incompatible input/output channels"; + + for (int i = 0; i < numSpatialDims; i++) { + if (inDims[i + 2] / blockSize != outDims[i + 2]) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << " has incompatible spatial dims"; + } + + auto computePrc = layer->insData[0].lock()->getTensorDesc().getPrecision(); + const std::set supported_precision_sizes = {1, 2, 4, 8}; + if (supported_precision_sizes.find(computePrc.size()) == supported_precision_sizes.end()) + THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << " doesn't support precision: " << computePrc.name(); + + + if (inDims.size() == 4 || inDims.size() == 5) { + LayerConfig config; + DataConfig inConfig; + inConfig.desc = TensorDesc(computePrc, inDims, inDims.size() == 4 ? NHWC : NDHWC); + config.inConfs.push_back(inConfig); + + DataConfig outConfig; + outConfig.desc = TensorDesc(computePrc, outDims, outDims.size() == 4 ? NHWC : NDHWC); + config.outConfs.push_back(outConfig); + + config.dynBatchSupport = false; + confs.push_back(config); + } + + LayerConfig config; + DataConfig inConfig; + inConfig.desc = TensorDesc(computePrc, inDims, InferenceEngine::TensorDesc::getLayoutByDims(inDims)); + config.inConfs.push_back(inConfig); + + DataConfig outConfig; + outConfig.desc = TensorDesc(computePrc, outDims, InferenceEngine::TensorDesc::getLayoutByDims(outDims)); + config.outConfs.push_back(outConfig); + + config.dynBatchSupport = false; + confs.push_back(config); } catch (InferenceEngine::details::InferenceEngineException &ex) { errorMsg = ex.what(); } } StatusCode execute(std::vector& inputs, std::vector& outputs, ResponseDesc *resp) noexcept override { - const float *src_data = inputs[0]->cbuffer().as() + - inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); - float* dst_data = outputs[0]->cbuffer().as() + - outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); - - // Parallel - parallel_nt(0, [&](const int ithr, const int nthr) { - size_t i, start = 0, end = 0, dst_idx = 0; - size_t counters[CNTR_SIZE] = { 0 }; - splitter(work_amount_dst, nthr, ithr, start, end); - i = start; - for (int j = CNTR_SIZE - 1; j >= 0; j--) { - counters[j] = i % own_dims[j]; - dst_idx += counters[j] * ownStrides[j]; - i /= own_dims[j]; - } - - for (size_t iwork = start, i = 1; iwork < end; ++iwork) { - dst_data[dst_idx] = src_data[iwork]; - for (int j = CNTR_SIZE - 1; j >= 0; j--) { - counters[j]++; - if (counters[j] < own_dims[j]) { - dst_idx += ownStrides[j]; - break; - } else { - counters[j] = i = 0; - } - } - if (!i) { - for (dst_idx = 0; i < CNTR_SIZE; ++i) - dst_idx += counters[i] * ownStrides[i]; + switch (inputs[0]->getTensorDesc().getPrecision().size()) { + case 1: spaceToDepthKernel::value_type>(inputs, outputs); break; + case 2: spaceToDepthKernel::value_type>(inputs, outputs); break; + case 4: spaceToDepthKernel::value_type>(inputs, outputs); break; + case 8: spaceToDepthKernel::value_type>(inputs, outputs); break; + default: { + if (resp) { + std::string errorMsg = "SpaceToDepth layer with name does not support precision '" + + std::string(inputs[0]->getTensorDesc().getPrecision().name()) + "'"; + errorMsg.copy(resp->msg, sizeof(resp->msg) - 1); + + return GENERAL_ERROR; } } - }); + } return OK; } private: - size_t work_amount_dst; - size_t own_dims[CNTR_SIZE]; - size_t ownStrides[CNTR_SIZE]; + std::vector getShape5D(const SizeVector& shape) { + std::vector shape5D(5, 1); + for (int i = 0; i < shape.size(); i++) { + shape5D[i] = shape[i]; + } + return shape5D; + } + + std::vector getBlock3D(const SizeVector& shape, const SizeVector& shape5D) { + std::vector block3D(3, 1); + for (int i = 0; i < shape.size() - 2; i++) { + block3D[i] = blockSize; + } + return block3D; + } + + template + void spaceToDepthKernel(std::vector& inputs, std::vector& outputs) { + const T *src_data = inputs[0]->cbuffer().as() + inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + T* dst_data = outputs[0]->buffer().as() + outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + + auto shape5D = getShape5D(outDims); + auto block3D = getBlock3D(outDims, shape5D); + + size_t spatialStep = shape5D[2] * shape5D[3] * shape5D[4]; + size_t batchStep = shape5D[1] * spatialStep; + + size_t dstChannels = shape5D[1]; + size_t srcChannels = dstChannels / blockStep; + + size_t blockShift = mode == SpaceToDepthMode::BLOCKS_FIRST ? (srcChannels) : 1; + size_t channelShift = mode == SpaceToDepthMode::BLOCKS_FIRST ? 1 : blockStep; + + if (inputs[0]->getTensorDesc().getLayout() == NHWC || inputs[0]->getTensorDesc().getLayout() == NDHWC) { + parallel_for2d(shape5D[0], shape5D[2], [&](size_t i0, size_t i2) { + size_t srcIdx1 = i0 * batchStep; + size_t dstIdx1 = i0 * batchStep; + for (size_t b2 = 0; b2 < block3D[0]; b2++) { + size_t srcIdx2 = srcIdx1 + (i2 * block3D[0] + b2) * shape5D[3] * block3D[1] * shape5D[4] * block3D[2] * srcChannels; + size_t dstIdx2 = dstIdx1 + i2 * shape5D[3] * shape5D[4] * dstChannels + b2 * block3D[1] * block3D[2] * blockShift; + for (size_t i3 = 0; i3 < shape5D[3]; i3++) { + for (size_t b3 = 0; b3 < block3D[1]; b3++) { + size_t dstIdx3 = dstIdx2 + i3 * shape5D[4] * dstChannels + b3 * block3D[2] * blockShift; + size_t srcIdx3 = srcIdx2 + (i3 * block3D[1] + b3) * shape5D[4] * block3D[2] * srcChannels; + for (size_t i4 = 0; i4 < shape5D[4]; i4++) { + for (size_t b4 = 0; b4 < block3D[2]; b4++) { + size_t srcIdx4 = srcIdx3 + (i4 * block3D[2] + b4) * srcChannels; + size_t dstIdx4 = dstIdx3 + i4 * dstChannels + b4 * blockShift; + for (size_t i1 = 0; i1 < srcChannels; i1++) { + size_t srcIdx5 = srcIdx4 + i1; + size_t dstIdx5 = dstIdx4 + i1 * channelShift; + dst_data[dstIdx5] = src_data[srcIdx5]; + } + } + } + } + } + } + }); + } else { + parallel_for2d(shape5D[0], srcChannels, [&](size_t i0, size_t i1) { + size_t srcIdx1 = i0 * batchStep + i1 * blockStep * spatialStep; + size_t dstIdx1 = i0 * batchStep + i1 * channelShift * spatialStep; + for (size_t i2 = 0; i2 < shape5D[2]; i2++) { + for (size_t b2 = 0; b2 < block3D[0]; b2++) { + size_t srcIdx2 = srcIdx1 + (i2 * block3D[0] + b2) * shape5D[3] * block3D[1] * shape5D[4] * block3D[2]; + size_t dstIdx2 = dstIdx1 + i2 * shape5D[3] * shape5D[4] + b2 * block3D[1] * block3D[2] * blockShift * spatialStep; + for (size_t i3 = 0; i3 < shape5D[3]; i3++) { + for (size_t b3 = 0; b3 < block3D[1]; b3++) { + size_t srcIdx3 = srcIdx2 + (i3 * block3D[1] + b3) * shape5D[4] * block3D[2]; + size_t dstIdx3 = dstIdx2 + i3 * shape5D[4] + b3 * block3D[2] * blockShift * spatialStep; + for (size_t i4 = 0; i4 < shape5D[4]; i4++) { + for (size_t b4 = 0; b4 < block3D[2]; b4++) { + size_t srcIdx4 = srcIdx3 + i4 * block3D[2] + b4; + size_t dstIdx4 = dstIdx3 + i4 + b4 * blockShift * spatialStep; + dst_data[dstIdx4] = src_data[srcIdx4]; + } + } + } + } + } + } + }); + } + } + + SpaceToDepthMode mode; + SizeVector outDims; + size_t blockSize; + size_t blockStep; }; REG_FACTORY_FOR(SpaceToDepthImpl, SpaceToDepth); diff --git a/inference-engine/src/transformations/include/transformations/common_optimizations/common_optimizations.hpp b/inference-engine/src/transformations/include/transformations/common_optimizations/common_optimizations.hpp index 3ead06ce6e9f46..cfbabbe7dcc57a 100644 --- a/inference-engine/src/transformations/include/transformations/common_optimizations/common_optimizations.hpp +++ b/inference-engine/src/transformations/include/transformations/common_optimizations/common_optimizations.hpp @@ -21,9 +21,10 @@ class TRANSFORMATIONS_API CommonOptimizations; } // namespace pass } // namespace ngraph -class ngraph::pass::CommonOptimizations: public ngraph::pass::FunctionPass { +class ngraph::pass::CommonOptimizations: public ngraph::pass::FunctionPass, public ngraph::pass::PassParam { public: - explicit CommonOptimizations() : FunctionPass() {} + explicit CommonOptimizations(const PassParam::param_callback & callback = PassParam::getDefaultCallback()) + : FunctionPass(), PassParam(callback) {} bool run_on_function(std::shared_ptr f) override; }; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp index 5b1a956d187737..6091fbd01d7417 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp @@ -20,11 +20,17 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr f) { ngraph::pass::Manager CommonOptimizations; + std::vector > transforms; -#define NGRAPH_PASS(NAME, NAMESPACE) CommonOptimizations.register_pass(); +#define NGRAPH_PASS(NAME, NAMESPACE) transforms.push_back(CommonOptimizations.register_pass()); #include #undef NGRAPH_PASS + for (auto & t : transforms) { + if (auto t_param = std::dynamic_pointer_cast(t)) { + t_param->setCallback(transformation_callback); + } + } CommonOptimizations.run_passes(f); return true; } diff --git a/inference-engine/src/transformations/src/transformations/depth_to_space_fusion.cpp b/inference-engine/src/transformations/src/transformations/depth_to_space_fusion.cpp index a2323b1620281d..d6c98e55e2defd 100644 --- a/inference-engine/src/transformations/src/transformations/depth_to_space_fusion.cpp +++ b/inference-engine/src/transformations/src/transformations/depth_to_space_fusion.cpp @@ -91,10 +91,6 @@ void ngraph::pass::DepthToSpaceFusion::depth_to_space_fusion() { auto reshape_after = std::make_shared (permute, input3, false); ngraph::graph_rewrite_callback callback = [this](pattern::Matcher& m) { - if (!transformation_callback(std::make_shared())) { - return false; - } - auto reshape_after = std::dynamic_pointer_cast(m.get_match_root()); if (!reshape_after) { return false; @@ -157,6 +153,11 @@ void ngraph::pass::DepthToSpaceFusion::depth_to_space_fusion() { std::make_shared(reshape_before->input_value(0), mode, block_size); depth_to_space->set_friendly_name(reshape_after->get_friendly_name()); ngraph::copy_runtime_info({reshape_before, permute, reshape_after}, depth_to_space); + + if (!transformation_callback(depth_to_space)) { + return false; + } + ngraph::replace_node(reshape_after, depth_to_space); return true; }; diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/depth_to_space.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/depth_to_space.cpp new file mode 100644 index 00000000000000..b9d5b70f66c162 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/depth_to_space.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "single_layer_tests/depth_to_space.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace ngraph::opset3; + +namespace { +const std::vector inputPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::U8, + InferenceEngine::Precision::I16, +}; + +const std::vector modes = { + DepthToSpace::DepthToSpaceMode::BLOCKS_FIRST, + DepthToSpace::DepthToSpaceMode::DEPTH_FIRST}; + +const std::vector> inputShapesBS2 = { + {1, 4, 1, 1}, {1, 4, 2, 2}, {1, 4, 3, 3}, {2, 32, 3, 3}, {2, 16, 5, 4}, + {1, 8, 1, 1, 1}, {1, 8, 2, 2, 2}, {1, 8, 3, 3, 3}, {2, 32, 3, 3, 3}, {2, 16, 5, 4, 6}}; + +const auto DepthToSpaceBS2 = ::testing::Combine( + ::testing::ValuesIn(inputShapesBS2), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(modes), + ::testing::Values(2), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P(DepthToSpaceBS2, DepthToSpaceLayerTest, DepthToSpaceBS2, DepthToSpaceLayerTest::getTestCaseName); + +const std::vector> inputShapesBS3 = { + {1, 9, 1, 1}, {1, 9, 2, 2}, {1, 9, 3, 3}, {2, 36, 3, 3}, {2, 27, 5, 4}, + {1, 27, 1, 1, 1}, {1, 27, 2, 2, 2}, {1, 27, 3, 3, 3}, {2, 108, 3, 3, 3}, {2, 54, 5, 4, 6}}; + +const auto DepthToSpaceBS3 = ::testing::Combine( + ::testing::ValuesIn(inputShapesBS3), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(modes), + ::testing::Values(3), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P(DepthToSpaceBS3, DepthToSpaceLayerTest, DepthToSpaceBS3, DepthToSpaceLayerTest::getTestCaseName); + +} // namespace \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/space_to_depth.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/space_to_depth.cpp new file mode 100644 index 00000000000000..ac1b4f4e99d117 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/space_to_depth.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "single_layer_tests/space_to_depth.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace ngraph::opset3; + +namespace { +const std::vector inputPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::U8, + InferenceEngine::Precision::I16, +}; + +const std::vector modes = { + SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST, + SpaceToDepth::SpaceToDepthMode::DEPTH_FIRST}; + +const std::vector> inputShapesBS2 = { + {1, 1, 2, 2}, {1, 1, 4, 4}, {1, 1, 6, 6}, {2, 8, 6, 6}, {2, 4, 10, 8}, + {1, 1, 2, 2, 2}, {1, 1, 4, 4, 4}, {1, 1, 6, 6, 6}, {2, 8, 6, 6, 6}, {2, 4, 10, 8, 12}}; + +const auto SpaceToDepthBS2 = ::testing::Combine( + ::testing::ValuesIn(inputShapesBS2), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(modes), + ::testing::Values(2), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P(SpaceToDepthBS2, SpaceToDepthLayerTest, SpaceToDepthBS2, SpaceToDepthLayerTest::getTestCaseName); + +const std::vector> inputShapesBS3 = { + {1, 1, 3, 3}, {1, 1, 6, 6}, {1, 1, 9, 9}, {2, 4, 9, 9}, {2, 3, 15, 12}, + {1, 1, 3, 3, 3}, {1, 1, 6, 6, 6}, {1, 1, 9, 9, 9}, {2, 4, 9, 9, 9}, {2, 3, 15, 12, 18}}; + +const auto SpaceToDepthBS3 = ::testing::Combine( + ::testing::ValuesIn(inputShapesBS3), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(modes), + ::testing::Values(3), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P(SpaceToDepthBS3, SpaceToDepthLayerTest, SpaceToDepthBS3, SpaceToDepthLayerTest::getTestCaseName); + +} // namespace \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/depth_to_space.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/depth_to_space.hpp new file mode 100644 index 00000000000000..7467a1da13a095 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/depth_to_space.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include + +#include "functional_test_utils/layer_test_utils.hpp" + +namespace LayerTestsDefinitions { + +using depthToSpaceParamsTuple = typename std::tuple< + std::vector, // Input shape + InferenceEngine::Precision, // Input precision + ngraph::opset3::DepthToSpace::DepthToSpaceMode, // Mode + std::size_t, // Block size + std::string>; // Device name> + +class DepthToSpaceLayerTest : public testing::WithParamInterface, + public LayerTestsUtils::LayerTestsCommon { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + +protected: + void SetUp() override; +}; + +} // namespace LayerTestsDefinitions \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/space_to_depth.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/space_to_depth.hpp new file mode 100644 index 00000000000000..c86410cc669214 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/space_to_depth.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include + +#include "functional_test_utils/layer_test_utils.hpp" + +namespace LayerTestsDefinitions { + +using spaceToDepthParamsTuple = typename std::tuple< + std::vector, // Input shape + InferenceEngine::Precision, // Input precision + ngraph::opset3::SpaceToDepth::SpaceToDepthMode, // Mode + std::size_t, // Block size + std::string>; // Device name> + +class SpaceToDepthLayerTest : public testing::WithParamInterface, + public LayerTestsUtils::LayerTestsCommon { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + +protected: + void SetUp() override; +}; + +} // namespace LayerTestsDefinitions \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/depth_to_space.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/depth_to_space.cpp new file mode 100644 index 00000000000000..30124195a7c2d2 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/depth_to_space.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "functional_test_utils/blob_utils.hpp" +#include "functional_test_utils/precision_utils.hpp" +#include "common_test_utils/common_utils.hpp" + +#include "single_layer_tests/depth_to_space.hpp" + +using namespace ngraph::opset3; + +namespace LayerTestsDefinitions { + +static inline std::string DepthToSpaceModeToString(const DepthToSpace::DepthToSpaceMode& mode) { + static std::map names = { + {DepthToSpace::DepthToSpaceMode::BLOCKS_FIRST, "BLOCKS_FIRST"}, + {DepthToSpace::DepthToSpaceMode::DEPTH_FIRST, "DEPTH_FIRST"}, + }; + + auto i = names.find(mode); + if (i != names.end()) + return i->second; + else + throw std::runtime_error("Unsupported DepthToSpaceMode"); +} + +std::string DepthToSpaceLayerTest::getTestCaseName(const testing::TestParamInfo &obj) { + std::vector inShape; + DepthToSpace::DepthToSpaceMode mode; + std::size_t blockSize; + InferenceEngine::Precision inputPrecision; + std::string targetName; + std::tie(inShape, inputPrecision, mode, blockSize, targetName) = obj.param; + std::ostringstream result; + result << "IS=" << CommonTestUtils::vec2str(inShape) << "_"; + result << "inPrc=" << inputPrecision.name() << "_"; + result << "M=" << DepthToSpaceModeToString(mode) << "_"; + result << "BS=" << blockSize << "_"; + result << "targetDevice=" << targetName << "_"; + return result.str(); +} + +void DepthToSpaceLayerTest::SetUp() { + std::vector inShape; + DepthToSpace::DepthToSpaceMode mode; + std::size_t blockSize; + InferenceEngine::Precision inputPrecision; + std::tie(inShape, inputPrecision, mode, blockSize, targetDevice) = this->GetParam(); + auto inPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inputPrecision); + auto params = ngraph::builder::makeParams(inPrc, {inShape}); + auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes(params)); + auto d2s = ngraph::builder::makeDepthToSpace(paramOuts[0], mode, blockSize); + ngraph::ResultVector results{std::make_shared(d2s)}; + function = std::make_shared(results, params, "DepthToSpace"); +} + +TEST_P(DepthToSpaceLayerTest, CompareWithRefs) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/space_to_depth.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/space_to_depth.cpp new file mode 100644 index 00000000000000..ff61a2ae7515c1 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/space_to_depth.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "functional_test_utils/blob_utils.hpp" +#include "functional_test_utils/precision_utils.hpp" +#include "common_test_utils/common_utils.hpp" + +#include "single_layer_tests/space_to_depth.hpp" + +using namespace ngraph::opset3; + +namespace LayerTestsDefinitions { + +static inline std::string SpaceToDepthModeToString(const SpaceToDepth::SpaceToDepthMode& mode) { + static std::map names = { + {SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST, "BLOCKS_FIRST"}, + {SpaceToDepth::SpaceToDepthMode::DEPTH_FIRST, "DEPTH_FIRST"}, + }; + + auto i = names.find(mode); + if (i != names.end()) + return i->second; + else + throw std::runtime_error("Unsupported SpaceToDepthMode"); +} + +std::string SpaceToDepthLayerTest::getTestCaseName(const testing::TestParamInfo &obj) { + std::vector inShape; + SpaceToDepth::SpaceToDepthMode mode; + std::size_t blockSize; + InferenceEngine::Precision inputPrecision; + std::string targetName; + std::tie(inShape, inputPrecision, mode, blockSize, targetName) = obj.param; + std::ostringstream result; + result << "IS=" << CommonTestUtils::vec2str(inShape) << "_"; + result << "inPrc=" << inputPrecision.name() << "_"; + result << "M=" << SpaceToDepthModeToString(mode) << "_"; + result << "BS=" << blockSize << "_"; + result << "targetDevice=" << targetName << "_"; + return result.str(); +} + +void SpaceToDepthLayerTest::SetUp() { + std::vector inShape; + SpaceToDepth::SpaceToDepthMode mode; + std::size_t blockSize; + InferenceEngine::Precision inputPrecision; + std::tie(inShape, inputPrecision, mode, blockSize, targetDevice) = this->GetParam(); + auto inPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inputPrecision); + auto params = ngraph::builder::makeParams(inPrc, {inShape}); + auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes(params)); + auto s2d = ngraph::builder::makeSpaceToDepth(paramOuts[0], mode, blockSize); + ngraph::ResultVector results{std::make_shared(s2d)}; + function = std::make_shared(results, params, "SpaceToDepth"); +} + +TEST_P(SpaceToDepthLayerTest, CompareWithRefs) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp index ccb4f882f109fe..26eb615f75a002 100644 --- a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp +++ b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp @@ -212,6 +212,13 @@ std::shared_ptr makeEmbeddingSegmentsSum( bool with_weights, bool with_default_index); +std::shared_ptr makeDepthToSpace(const ngraph::Output &in, + ngraph::opset3::DepthToSpace::DepthToSpaceMode mode, + size_t blockSize); + +std::shared_ptr makeSpaceToDepth(const ngraph::Output &in, + ngraph::opset3::SpaceToDepth::SpaceToDepthMode mode, + size_t blockSize); } // namespace builder } // namespace ngraph diff --git a/inference-engine/tests/ngraph_functions/src/depth_to_space.cpp b/inference-engine/tests/ngraph_functions/src/depth_to_space.cpp new file mode 100644 index 00000000000000..f7e41d3179ad38 --- /dev/null +++ b/inference-engine/tests/ngraph_functions/src/depth_to_space.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph_functions/builders.hpp" + +namespace ngraph { +namespace builder { + +std::shared_ptr makeDepthToSpace(const ngraph::Output &in, + ngraph::opset3::DepthToSpace::DepthToSpaceMode mode, + size_t blockSize) { + auto dtsNode = std::make_shared(in, mode, blockSize); + return dtsNode; +} + +} // namespace builder +} // namespace ngraph \ No newline at end of file diff --git a/inference-engine/tests/ngraph_functions/src/space_to_depth.cpp b/inference-engine/tests/ngraph_functions/src/space_to_depth.cpp new file mode 100644 index 00000000000000..8d7d279c3d0128 --- /dev/null +++ b/inference-engine/tests/ngraph_functions/src/space_to_depth.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph_functions/builders.hpp" + +namespace ngraph { +namespace builder { + +std::shared_ptr makeSpaceToDepth(const ngraph::Output &in, + ngraph::opset3::SpaceToDepth::SpaceToDepthMode mode, + size_t blockSize) { + auto dtsNode = std::make_shared(in, mode, blockSize); + return dtsNode; +} + +} // namespace builder +} // namespace ngraph \ No newline at end of file diff --git a/inference-engine/tests_deprecated/unit/engines/mkldnn/graph/layers/extensions/depth_to_space_tests.cpp b/inference-engine/tests_deprecated/unit/engines/mkldnn/graph/layers/extensions/depth_to_space_tests.cpp deleted file mode 100644 index 5cbfc981d49459..00000000000000 --- a/inference-engine/tests_deprecated/unit/engines/mkldnn/graph/layers/extensions/depth_to_space_tests.cpp +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright (C) 2018-2020 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#include "test_graph.hpp" - -#include "single_layer_common.hpp" -#include "tests_common.hpp" -#include - - -using namespace ::testing; -using namespace std; -using namespace mkldnn; - -struct depth_to_space_test_params { - InferenceEngine::SizeVector in_shape; - size_t block_size; - InferenceEngine::SizeVector out_shape; - - std::vector reference; - std::vector> comp; -}; - -void ref_depth_to_space( - InferenceEngine::TBlob &src, - InferenceEngine::TBlob &dst, - size_t block_size -) { - size_t i; - const float *src_data = src.data(); - InferenceEngine::SizeVector src_dims = src.getTensorDesc().getDims(); - InferenceEngine::SizeVector srcStrides = src.getTensorDesc().getBlockingDesc().getStrides(); - float* dst_data = dst.data(); - InferenceEngine::SizeVector dst_dims = dst.getTensorDesc().getDims(); - InferenceEngine::SizeVector dstStrides = dst.getTensorDesc().getBlockingDesc().getStrides(); - - if (src_dims.size() < 3) - FAIL() << " Incorrect number of input dimensions!"; - - if (dst_dims.size() < 2) - FAIL() << " Incorrect number of output dimensions!"; - - if (block_size == 0) - FAIL() << " Incorrect block_size parameter is zero!"; - - if (src_dims[src_dims.size() - 3] % (block_size * block_size)) - FAIL() << " block_size parameter is incompatible with input tensor Color dimension size!"; - - if (dst_dims.size() > 2 && src_dims[src_dims.size() - 3] != (dst_dims[dst_dims.size() - 3] * block_size * block_size)) - FAIL() << " Input/Output tensor Color dimension is incompatible with block_size!"; - - if (dst_dims[dst_dims.size() - 2] != (src_dims[src_dims.size() - 2] * block_size)) - FAIL() << " Input/Output tensor Height dimension is incompatible with block_size!"; - - if (dst_dims[dst_dims.size() - 1] != (src_dims[src_dims.size() - 1] * block_size)) - FAIL() << " Input/Output tensor Width dimension is incompatible with block_size!"; - - size_t X = 1; - for (i = 0; i < (src_dims.size() - 3); i++) - X *= src_dims[i]; - - size_t C = src_dims[src_dims.size() - 3]; - size_t H = src_dims[src_dims.size() - 2]; - size_t W = src_dims[src_dims.size() - 1]; - - for (size_t x = 0, k = 0; x < X; ++x) { - for (size_t h = 0; h < H; ++h) { - for (size_t c = 0; c < C; c += block_size) { - for (size_t w = 0; w < W; ++w) { - for (size_t b = 0; b < block_size; ++b) { - size_t idx = x * C*H*W + (c + b) * H*W + h * W + w; - dst_data[k++] = src_data[idx]; - } - } - } - } - } -} - -void ref_space_to_depth( - InferenceEngine::TBlob &src, - InferenceEngine::TBlob &dst, - size_t block_size -) { - size_t i; - const float *src_data = src.data(); - InferenceEngine::SizeVector src_dims = src.getTensorDesc().getDims(); - InferenceEngine::SizeVector srcStrides = src.getTensorDesc().getBlockingDesc().getStrides(); - float* dst_data = dst.data(); - InferenceEngine::SizeVector dst_dims = dst.getTensorDesc().getDims(); - InferenceEngine::SizeVector dstStrides = dst.getTensorDesc().getBlockingDesc().getStrides(); - - if (dst_dims.size() < 3) - FAIL() << " Incorrect number of output dimensions!"; - - if (src_dims.size() < 2) - FAIL() << " Incorrect number of input dimensions!"; - - if (block_size == 0) - FAIL() << " Incorrect block_size parameter is zero!"; - - if (dst_dims[dst_dims.size() - 3] % (block_size * block_size)) - FAIL() << " block_size parameter is incompatible with input tensor Color dimension size!"; - - if (src_dims.size() > 2 && dst_dims[dst_dims.size() - 3] != (src_dims[dst_dims.size() - 3] * block_size * block_size)) - FAIL() << " Input/Output tensor Color dimension is incompatible with block_size!"; - - if (src_dims[src_dims.size() - 2] != (dst_dims[dst_dims.size() - 2] * block_size)) - FAIL() << " Input/Output tensor Height dimension is incompatible with block_size!"; - - if (src_dims[src_dims.size() - 1] != (dst_dims[dst_dims.size() - 1] * block_size)) - FAIL() << " Input/Output tensor Width dimension is incompatible with block_size!"; - - size_t X = 1; - for (i = 0; i < (dst_dims.size() - 3); i++) - X *= dst_dims[i]; - - size_t C = dst_dims[dst_dims.size() - 3]; - size_t H = dst_dims[dst_dims.size() - 2]; - size_t W = dst_dims[dst_dims.size() - 1]; - - for (size_t x = 0, k = 0; x < X; ++x) { - for (size_t h = 0; h < H; ++h) { - for (size_t c = 0; c < C; c += block_size) { - for (size_t w = 0; w < W; ++w) { - for (size_t b = 0; b < block_size; ++b) { - size_t idx = x * C*H*W + (c + b) * H*W + h * W + w; - dst_data[idx] = src_data[k++]; - } - } - } - } - } -} - -class MKLDNNCPUExtDepthToSpaceTests : public TestsCommon, public WithParamInterface { - std::string model_t = R"V0G0N( - - - - - - _IN_ - - s - - - - - - _IN_ - - - - - _OUT_ - - - - - - - - -)V0G0N"; - - std::string getModel(depth_to_space_test_params p) { - std::string model = model_t; - std::string in_shape, out_shape; - - for (size_t i = 0; i < p.in_shape.size(); i++) { - in_shape += ""; - in_shape += std::to_string(p.in_shape[i]) + "\n"; - } - for (size_t i = 0; i < p.out_shape.size(); i++) { - out_shape += ""; - out_shape += std::to_string(p.out_shape[i]) + "\n"; - } - REPLACE_WITH_STR(model, "_IN_", in_shape); - REPLACE_WITH_STR(model, "_OUT_", out_shape); - REPLACE_WITH_NUM(model, "_BS_", p.block_size); - - return model; - } - -protected: - virtual void TearDown() { - } - - virtual void SetUp() { - try { - TestsCommon::SetUp(); - depth_to_space_test_params p = ::testing::WithParamInterface::GetParam(); - std::string model = getModel(p); - - InferenceEngine::Core core; - InferenceEngine::CNNNetwork network; - ASSERT_NO_THROW(network = core.ReadNetwork(model, InferenceEngine::Blob::CPtr())); - - MKLDNNGraphTestClass graph; - graph.CreateGraph(network); - - // Output Data - InferenceEngine::OutputsDataMap out; - out = network.getOutputsInfo(); - InferenceEngine::BlobMap outputBlobs; - - std::pair item = *out.begin(); - - InferenceEngine::TBlob::Ptr output; - output = InferenceEngine::make_shared_blob(item.second->getTensorDesc()); - output->allocate(); - outputBlobs[item.first] = output; - - // Output Reference - InferenceEngine::TBlob dst_ref(item.second->getTensorDesc()); - dst_ref.allocate(); - - // Input Data - InferenceEngine::Blob::Ptr src; - src = InferenceEngine::make_shared_blob({ InferenceEngine::Precision::FP32, p.in_shape, InferenceEngine::TensorDesc::getLayoutByDims(p.in_shape) }); - src->allocate(); - fill_data_dbgval(src->buffer(), src->size()); - auto * srcPtr = dynamic_cast*>(src.get()); - if (srcPtr == nullptr) - FAIL() << "Cannot cast blob to TBlob."; - - // Check results - InferenceEngine::SizeVector out_dims; - ref_depth_to_space(*srcPtr, dst_ref, p.block_size); - - // Check results - if(p.reference.size()) - if (memcmp(dst_ref.data(), &p.reference[0], p.reference.size() * sizeof(float)) != 0) - FAIL() << "Wrong result with compare TF reference!"; - - InferenceEngine::BlobMap srcs; - srcs.insert(std::pair("input", src)); - - // Infer - graph.Infer(srcs, outputBlobs); - compare(*output, dst_ref); - } catch (const InferenceEngine::details::InferenceEngineException &e) { - FAIL() << e.what(); - } - } -}; - -class MKLDNNCPUExtSpaceToDepthTests : public TestsCommon, public WithParamInterface { - std::string model_t = R"V0G0N( - - - - - - _IN_ - - s - - - - - - _IN_ - - - - - _OUT_ - - - - - - - - -)V0G0N"; - - std::string getModel(depth_to_space_test_params p) { - std::string model = model_t; - std::string in_shape, out_shape; - - for (size_t i = 0; i < p.out_shape.size(); i++) { - in_shape += ""; - in_shape += std::to_string(p.out_shape[i]) + "\n"; - } - for (size_t i = 0; i < p.in_shape.size(); i++) { - out_shape += ""; - out_shape += std::to_string(p.in_shape[i]) + "\n"; - } - REPLACE_WITH_STR(model, "_IN_", in_shape); - REPLACE_WITH_STR(model, "_OUT_", out_shape); - REPLACE_WITH_NUM(model, "_BS_", p.block_size); - - return model; - } - -protected: - virtual void TearDown() { - } - - virtual void SetUp() { - try { - TestsCommon::SetUp(); - depth_to_space_test_params p = ::testing::WithParamInterface::GetParam(); - std::string model = getModel(p); - //std::cout << model; - InferenceEngine::Core core; - InferenceEngine::CNNNetwork network; - ASSERT_NO_THROW(network = core.ReadNetwork(model, InferenceEngine::Blob::CPtr())); - - MKLDNNGraphTestClass graph; - graph.CreateGraph(network); - - // Output Data - InferenceEngine::OutputsDataMap out; - out = network.getOutputsInfo(); - InferenceEngine::BlobMap outputBlobs; - - std::pair item = *out.begin(); - - InferenceEngine::TBlob::Ptr output; - output = InferenceEngine::make_shared_blob(item.second->getTensorDesc()); - output->allocate(); - outputBlobs[item.first] = output; - - // Output Reference - InferenceEngine::TBlob dst_ref(item.second->getTensorDesc()); - dst_ref.allocate(); - - // Input Data - InferenceEngine::Blob::Ptr src; - src = InferenceEngine::make_shared_blob({ InferenceEngine::Precision::FP32, p.out_shape, InferenceEngine::TensorDesc::getLayoutByDims(p.out_shape) }); - src->allocate(); - if (p.reference.size()) - memcpy(static_cast(src->buffer()), &p.reference[0], sizeof(float)*p.reference.size()); - auto * srcPtr = dynamic_cast*>(src.get()); - if (srcPtr == nullptr) - FAIL() << "Cannot cast blob to TBlob."; - - // Check results - InferenceEngine::SizeVector out_dims; - ref_space_to_depth(*srcPtr, dst_ref, p.block_size); - - // Check results - if (p.reference.size()) { - // fill_data_dbgval(src->buffer(), src->size()); - // if (memcmp(dst_ref.data(), &p.reference[0], p.reference.size() * sizeof(float)) != 0) - // FAIL() << "Wrong result with compare TF reference!"; - } - - InferenceEngine::BlobMap srcs; - srcs.insert(std::pair("input", src)); - - // Infer - graph.Infer(srcs, outputBlobs); - compare(*output, dst_ref); - } - catch (const InferenceEngine::details::InferenceEngineException &e) { - FAIL() << e.what(); - } - } -}; - - - -class MKLDNNCPUExtDepthToSpaceToDepthTests : public TestsCommon, public WithParamInterface { - std::string model_t = R"V0G0N( - - - - - - _IN_ - - s - - - - - - _IN_ - - - - - _OUT_ - - - - - - - - _OUT_ - - - - - _IN_ - - - - - - - - - -)V0G0N"; - - std::string getModel(depth_to_space_test_params p) { - std::string model = model_t; - std::string in_shape, out_shape; - - for (size_t i = 0; i < p.in_shape.size(); i++) { - in_shape += ""; - in_shape += std::to_string(p.in_shape[i]) + "\n"; - } - for (size_t i = 0; i < p.out_shape.size(); i++) { - out_shape += ""; - out_shape += std::to_string(p.out_shape[i]) + "\n"; - } - REPLACE_WITH_STR(model, "_IN_", in_shape); - REPLACE_WITH_STR(model, "_OUT_", out_shape); - REPLACE_WITH_NUM(model, "_BS_", p.block_size); - - return model; - } - -protected: - virtual void TearDown() { - } - - virtual void SetUp() { - try { - TestsCommon::SetUp(); - depth_to_space_test_params p = ::testing::WithParamInterface::GetParam(); - std::string model = getModel(p); - - InferenceEngine::Core core; - InferenceEngine::CNNNetwork network; - ASSERT_NO_THROW(network = core.ReadNetwork(model, InferenceEngine::Blob::CPtr())); - - MKLDNNGraphTestClass graph; - graph.CreateGraph(network); - - // Output Data - InferenceEngine::OutputsDataMap out; - out = network.getOutputsInfo(); - InferenceEngine::BlobMap outputBlobs; - - std::pair item = *out.begin(); - - InferenceEngine::TBlob::Ptr output; - output = InferenceEngine::make_shared_blob(item.second->getTensorDesc()); - output->allocate(); - outputBlobs[item.first] = output; - - // Input Data - InferenceEngine::Blob::Ptr src; - src = InferenceEngine::make_shared_blob({ InferenceEngine::Precision::FP32, p.in_shape, InferenceEngine::TensorDesc::getLayoutByDims(p.in_shape) }); - src->allocate(); - fill_data_dbgval(src->buffer(), src->size()); - auto * srcPtr = dynamic_cast*>(src.get()); - if (srcPtr == nullptr) - FAIL() << "Cannot cast blob to TBlob."; - - InferenceEngine::BlobMap srcs; - srcs.insert(std::pair("input", src)); - - // Infer - graph.Infer(srcs, outputBlobs); - compare(*output, *src); - } - catch (const InferenceEngine::details::InferenceEngineException &e) { - FAIL() << e.what(); - } - } -}; - -TEST_P(MKLDNNCPUExtDepthToSpaceTests, TestsDepthToSpace) {} -// Test data vectors -static std::vector test0 = { 0.f, 6.f, 1.f, 7.f, 2.f, 8.f, 12.f, 18.f, 13.f, 19.f, 14.f, 20.f, 3.f, 9.f, 4.f, 10.f, 5.f, 11.f, 15.f, 21.f, 16.f, 22.f, 17.f, 23.f}; -INSTANTIATE_TEST_CASE_P( - TestsDepthToSpace, MKLDNNCPUExtDepthToSpaceTests, - ::testing::Values( -// Params: in_shape, block_size, out_shape, reference - depth_to_space_test_params{ { 1, 4, 2, 3 }, 2, { 1, 1, 4, 6 }, test0 }, - depth_to_space_test_params{ { 4, 2, 3 }, 2, { 1, 1, 4, 6 }, test0 }, - depth_to_space_test_params{ { 1, 4, 2, 3 }, 2, { 4, 6 }, test0 }, - depth_to_space_test_params{ { 4, 2, 3 }, 2, { 4, 6 }, test0 }, - depth_to_space_test_params{ { 5, 4, 2, 3 }, 2, { 5, 1, 4, 6 }, test0 }, - depth_to_space_test_params{ { 2, 3, 5, 4, 2, 3 }, 2, { 2, 3, 5, 1, 4, 6 }, test0 } -)); - - -TEST_P(MKLDNNCPUExtDepthToSpaceToDepthTests, TestsDepthToSpaceToDepth) {} -INSTANTIATE_TEST_CASE_P( - TestsDepthToSpaceToDepth, MKLDNNCPUExtDepthToSpaceToDepthTests, - ::testing::Values( - // Params: in_shape, block_size, out_shape, reference - depth_to_space_test_params{ { 1, 9, 2, 3 }, 3,{ 1, 1, 6, 9 },{} }, - depth_to_space_test_params{ { 16, 2, 3 }, 4,{ 1, 1, 8, 12 },{} }, - depth_to_space_test_params{ { 1, 25, 4, 3 }, 5,{ 20, 15 },{} }, - depth_to_space_test_params{ { 72, 10, 3 }, 6,{ 2, 60, 18 },{} }, - depth_to_space_test_params{ { 5, 8, 2, 3 }, 2,{ 5, 2, 4, 6 },{} }, - depth_to_space_test_params{ { 2, 3, 5, 16, 2, 3 }, 2,{ 2, 3, 5, 4, 4, 6 },{} } -));