DepthToSpace, SpaceToDepth layers optimizations (#706)

* [CPU] Updated DepthToSpace and SpaceToDepth layers to be conformant with the specification

The patch also includes n[d]hwc layout support as well as some optimizations

* [CPU][TESTS] Removed old DepthToSpace test since it doesn't corresponds to layer's specification

* [nGraph] Utilize CommonOptimizations pass with custom transformations callback
This commit is contained in:
Gorokhov Dmitriy 2020-06-04 14:25:19 +03:00 committed by GitHub
parent 01e60d057d
commit 3183c116d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 723 additions and 666 deletions

View File

@ -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);

View File

@ -1371,9 +1371,9 @@ void DepthToSpaceValidator::checkShapes(const CNNLayer* layer, const vector<Size
if (casted->block_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<size_t>(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) {}

View File

@ -82,6 +82,16 @@ Engine::LoadExeNetworkImpl(const InferenceEngine::ICNNNetwork &network, const st
if (clonedNetwork->getFunction()) {
const auto transformations_callback = [](const std::shared_ptr<const ::ngraph::Node> &node) -> bool {
// DepthToSpace node implementation supports only equal input/output tensors with rank <= 5
if (auto dtsOp = std::dynamic_pointer_cast<const ::ngraph::opset3::DepthToSpace>(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<const ::ngraph::opset3::SpaceToDepth>(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<const ::ngraph::opset2::Gelu>(node) ||
std::dynamic_pointer_cast<const ::ngraph::opset2::BatchToSpace>(node) ||
std::dynamic_pointer_cast<const ::ngraph::opset2::SpaceToBatch>(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);

View File

@ -8,6 +8,7 @@
#include <string>
#include <vector>
#include <cassert>
#include <set>
#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!";
THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' has 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!";
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";
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!";
if (inDims.size() > 5)
THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' doesn't support dimensions with rank greater than 5";
size_t block_size = layer->GetParamAsUInt("block_size", 1);
if (block_size == 0)
THROW_IE_EXCEPTION << layer->name << " Incorrect block_size parameter is zero!";
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";
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!";
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;
}
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!";
blockSize = layer->GetParamAsUInt("block_size", 1);
if (blockSize == 0)
THROW_IE_EXCEPTION << layer->name << " Incorrect blockSize parameter is zero!";
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!";
size_t numSpatialDims = inDims.size() - 2;
blockStep = static_cast<size_t>(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 (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!";
if (inDims[1] / blockStep != outDims[1])
THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << " has incompatible input/output channels";
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;
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";
}
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];
auto computePrc = layer->insData[0].lock()->getTensorDesc().getPrecision();
const std::set<size_t> 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();
addConfig(layer, { DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) });
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<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
const float *src_data = inputs[0]->cbuffer().as<const float *>() +
inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
float* dst_data = outputs[0]->cbuffer().as<float *>() +
outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
switch (inputs[0]->getTensorDesc().getPrecision().size()) {
case 1: depthToSpaceKernel<PrecisionTrait<Precision::U8>::value_type>(inputs, outputs); break;
case 2: depthToSpaceKernel<PrecisionTrait<Precision::U16>::value_type>(inputs, outputs); break;
case 4: depthToSpaceKernel<PrecisionTrait<Precision::I32>::value_type>(inputs, outputs); break;
case 8: depthToSpaceKernel<PrecisionTrait<Precision::U64>::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);
// 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];
return GENERAL_ERROR;
}
}
});
}
return OK;
}
private:
size_t work_amount_dst;
size_t own_dims[CNTR_SIZE];
size_t ownStrides[CNTR_SIZE];
std::vector<size_t> getShape5D(const SizeVector& shape) {
std::vector<size_t> shape5D(5, 1);
for (int i = 0; i < shape.size(); i++) {
shape5D[i] = shape[i];
}
return shape5D;
}
std::vector<size_t> getBlock3D(const SizeVector& shape, const SizeVector& shape5D) {
std::vector<size_t> block3D(3, 1);
for (int i = 0; i < shape.size() - 2; i++) {
block3D[i] = blockSize;
}
return block3D;
}
template<typename T>
void depthToSpaceKernel(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs) {
const T *src_data = inputs[0]->cbuffer().as<const T *>() + inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
T* dst_data = outputs[0]->buffer().as<T *>() + 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);

View File

@ -8,6 +8,7 @@
#include <string>
#include <vector>
#include <cassert>
#include <set>
#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!";
THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << "' has 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 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";
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!";
if (inDims.size() > 5)
THROW_IE_EXCEPTION << "DepthToSpace layer with name '" << layer->name << "' doesn't support dimensions with rank greater than 5";
size_t block_size = layer->GetParamAsUInt("block_size", 1);
if (block_size == 0)
THROW_IE_EXCEPTION << layer->name << " Incorrect block_size parameter is zero!";
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";
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!";
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;
}
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!";
blockSize = layer->GetParamAsUInt("block_size", 1);
if (blockSize == 0)
THROW_IE_EXCEPTION << layer->name << " Incorrect blockSize parameter is zero!";
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!";
size_t numSpatialDims = inDims.size() - 2;
blockStep = static_cast<size_t>(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 (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!";
if (inDims[1] != outDims[1] / blockStep)
THROW_IE_EXCEPTION << "SpaceToDepth layer with name '" << layer->name << " has incompatible input/output channels";
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;
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";
}
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];
auto computePrc = layer->insData[0].lock()->getTensorDesc().getPrecision();
const std::set<size_t> 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();
addConfig(layer, { DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) });
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<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
const float *src_data = inputs[0]->cbuffer().as<const float *>() +
inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
float* dst_data = outputs[0]->cbuffer().as<float *>() +
outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
switch (inputs[0]->getTensorDesc().getPrecision().size()) {
case 1: spaceToDepthKernel<PrecisionTrait<Precision::U8>::value_type>(inputs, outputs); break;
case 2: spaceToDepthKernel<PrecisionTrait<Precision::U16>::value_type>(inputs, outputs); break;
case 4: spaceToDepthKernel<PrecisionTrait<Precision::I32>::value_type>(inputs, outputs); break;
case 8: spaceToDepthKernel<PrecisionTrait<Precision::U64>::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);
// 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];
return GENERAL_ERROR;
}
}
});
}
return OK;
}
private:
size_t work_amount_dst;
size_t own_dims[CNTR_SIZE];
size_t ownStrides[CNTR_SIZE];
std::vector<size_t> getShape5D(const SizeVector& shape) {
std::vector<size_t> shape5D(5, 1);
for (int i = 0; i < shape.size(); i++) {
shape5D[i] = shape[i];
}
return shape5D;
}
std::vector<size_t> getBlock3D(const SizeVector& shape, const SizeVector& shape5D) {
std::vector<size_t> block3D(3, 1);
for (int i = 0; i < shape.size() - 2; i++) {
block3D[i] = blockSize;
}
return block3D;
}
template<typename T>
void spaceToDepthKernel(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs) {
const T *src_data = inputs[0]->cbuffer().as<const T *>() + inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
T* dst_data = outputs[0]->buffer().as<T *>() + 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);

View File

@ -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<ngraph::Function> f) override;
};

View File

@ -20,11 +20,17 @@
bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr<ngraph::Function> f) {
ngraph::pass::Manager CommonOptimizations;
std::vector<std::shared_ptr<ngraph::pass::PassBase> > transforms;
#define NGRAPH_PASS(NAME, NAMESPACE) CommonOptimizations.register_pass<NAMESPACE::NAME>();
#define NGRAPH_PASS(NAME, NAMESPACE) transforms.push_back(CommonOptimizations.register_pass<NAMESPACE::NAME>());
#include <transformations/common_optimizations/common_optimizations_tbl.hpp>
#undef NGRAPH_PASS
for (auto & t : transforms) {
if (auto t_param = std::dynamic_pointer_cast<PassParam>(t)) {
t_param->setCallback(transformation_callback);
}
}
CommonOptimizations.run_passes(f);
return true;
}

View File

@ -91,10 +91,6 @@ void ngraph::pass::DepthToSpaceFusion::depth_to_space_fusion() {
auto reshape_after = std::make_shared<ngraph::opset3::Reshape> (permute, input3, false);
ngraph::graph_rewrite_callback callback = [this](pattern::Matcher& m) {
if (!transformation_callback(std::make_shared<ngraph::opset3::DepthToSpace>())) {
return false;
}
auto reshape_after = std::dynamic_pointer_cast<ngraph::opset3::Reshape>(m.get_match_root());
if (!reshape_after) {
return false;
@ -157,6 +153,11 @@ void ngraph::pass::DepthToSpaceFusion::depth_to_space_fusion() {
std::make_shared<ngraph::opset3::DepthToSpace>(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;
};

View File

@ -0,0 +1,53 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <ngraph/opsets/opset3.hpp>
#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<InferenceEngine::Precision> inputPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::U8,
InferenceEngine::Precision::I16,
};
const std::vector<DepthToSpace::DepthToSpaceMode> modes = {
DepthToSpace::DepthToSpaceMode::BLOCKS_FIRST,
DepthToSpace::DepthToSpaceMode::DEPTH_FIRST};
const std::vector<std::vector<size_t >> 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<std::vector<size_t >> 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

View File

@ -0,0 +1,53 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <ngraph/opsets/opset3.hpp>
#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<InferenceEngine::Precision> inputPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::U8,
InferenceEngine::Precision::I16,
};
const std::vector<SpaceToDepth::SpaceToDepthMode> modes = {
SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST,
SpaceToDepth::SpaceToDepthMode::DEPTH_FIRST};
const std::vector<std::vector<size_t >> 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<std::vector<size_t >> 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

View File

@ -0,0 +1,32 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "functional_test_utils/layer_test_utils.hpp"
namespace LayerTestsDefinitions {
using depthToSpaceParamsTuple = typename std::tuple<
std::vector<size_t>, // 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<depthToSpaceParamsTuple>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(const testing::TestParamInfo<depthToSpaceParamsTuple> &obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions

View File

@ -0,0 +1,32 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "functional_test_utils/layer_test_utils.hpp"
namespace LayerTestsDefinitions {
using spaceToDepthParamsTuple = typename std::tuple<
std::vector<size_t>, // 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<spaceToDepthParamsTuple>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(const testing::TestParamInfo<spaceToDepthParamsTuple> &obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions

View File

@ -0,0 +1,72 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include <ie_core.hpp>
#include <ngraph_functions/builders.hpp>
#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<DepthToSpace::DepthToSpaceMode, std::string> 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<depthToSpaceParamsTuple> &obj) {
std::vector<size_t> 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<size_t> 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<ngraph::op::Parameter>(params));
auto d2s = ngraph::builder::makeDepthToSpace(paramOuts[0], mode, blockSize);
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(d2s)};
function = std::make_shared<ngraph::Function>(results, params, "DepthToSpace");
}
TEST_P(DepthToSpaceLayerTest, CompareWithRefs) {
Run();
};
} // namespace LayerTestsDefinitions

View File

@ -0,0 +1,72 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include <ie_core.hpp>
#include <ngraph_functions/builders.hpp>
#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<SpaceToDepth::SpaceToDepthMode, std::string> 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<spaceToDepthParamsTuple> &obj) {
std::vector<size_t> 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<size_t> 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<ngraph::op::Parameter>(params));
auto s2d = ngraph::builder::makeSpaceToDepth(paramOuts[0], mode, blockSize);
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(s2d)};
function = std::make_shared<ngraph::Function>(results, params, "SpaceToDepth");
}
TEST_P(SpaceToDepthLayerTest, CompareWithRefs) {
Run();
};
} // namespace LayerTestsDefinitions

View File

@ -212,6 +212,13 @@ std::shared_ptr<ngraph::Node> makeEmbeddingSegmentsSum(
bool with_weights,
bool with_default_index);
std::shared_ptr<ngraph::Node> makeDepthToSpace(const ngraph::Output<Node> &in,
ngraph::opset3::DepthToSpace::DepthToSpaceMode mode,
size_t blockSize);
std::shared_ptr<ngraph::Node> makeSpaceToDepth(const ngraph::Output<Node> &in,
ngraph::opset3::SpaceToDepth::SpaceToDepthMode mode,
size_t blockSize);
} // namespace builder
} // namespace ngraph

View File

@ -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<ngraph::Node> makeDepthToSpace(const ngraph::Output<Node> &in,
ngraph::opset3::DepthToSpace::DepthToSpaceMode mode,
size_t blockSize) {
auto dtsNode = std::make_shared<ngraph::opset3::DepthToSpace>(in, mode, blockSize);
return dtsNode;
}
} // namespace builder
} // namespace ngraph

View File

@ -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<ngraph::Node> makeSpaceToDepth(const ngraph::Output<Node> &in,
ngraph::opset3::SpaceToDepth::SpaceToDepthMode mode,
size_t blockSize) {
auto dtsNode = std::make_shared<ngraph::opset3::SpaceToDepth>(in, mode, blockSize);
return dtsNode;
}
} // namespace builder
} // namespace ngraph

View File

@ -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 <ie_core.hpp>
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<float> reference;
std::vector<std::function<void(MKLDNNPlugin::PrimitiveDescInfo)>> comp;
};
void ref_depth_to_space(
InferenceEngine::TBlob<float> &src,
InferenceEngine::TBlob<float> &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<float> &src,
InferenceEngine::TBlob<float> &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<depth_to_space_test_params> {
std::string model_t = R"V0G0N(
<net Name="DepthToSpace_net" version="2" precision="FP32" batch="1">
<layers>
<layer name="input" type="Input" precision="FP32" id="1">
<output>
<port id="1">
_IN_
</port>
</output>s
</layer>
<layer name="output" id="2" type="DepthToSpace" precision="FP32">
<data block_size="_BS_"/>
<input>
<port id="1">
_IN_
</port>
</input>
<output>
<port id="2">
_OUT_
</port>
</output>
</layer>
</layers>
<edges>
<edge from-layer="1" from-port="1" to-layer="2" to-port="1"/>
</edges>
</net>
)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 += "<dim>";
in_shape += std::to_string(p.in_shape[i]) + "</dim>\n";
}
for (size_t i = 0; i < p.out_shape.size(); i++) {
out_shape += "<dim>";
out_shape += std::to_string(p.out_shape[i]) + "</dim>\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<depth_to_space_test_params>::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<std::string, InferenceEngine::DataPtr> item = *out.begin();
InferenceEngine::TBlob<float>::Ptr output;
output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
output->allocate();
outputBlobs[item.first] = output;
// Output Reference
InferenceEngine::TBlob<float> dst_ref(item.second->getTensorDesc());
dst_ref.allocate();
// Input Data
InferenceEngine::Blob::Ptr src;
src = InferenceEngine::make_shared_blob<float>({ 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<InferenceEngine::TBlob<float>*>(src.get());
if (srcPtr == nullptr)
FAIL() << "Cannot cast blob to TBlob<float>.";
// 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<std::string, InferenceEngine::Blob::Ptr>("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<depth_to_space_test_params> {
std::string model_t = R"V0G0N(
<net Name="SpaceToDepth_net" version="2" precision="FP32" batch="1">
<layers>
<layer name="input" type="Input" precision="FP32" id="1">
<output>
<port id="1">
_IN_
</port>
</output>s
</layer>
<layer name="output" id="2" type="SpaceToDepth" precision="FP32">
<data block_size="_BS_"/>
<input>
<port id="1">
_IN_
</port>
</input>
<output>
<port id="2">
_OUT_
</port>
</output>
</layer>
</layers>
<edges>
<edge from-layer="1" from-port="1" to-layer="2" to-port="1"/>
</edges>
</net>
)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 += "<dim>";
in_shape += std::to_string(p.out_shape[i]) + "</dim>\n";
}
for (size_t i = 0; i < p.in_shape.size(); i++) {
out_shape += "<dim>";
out_shape += std::to_string(p.in_shape[i]) + "</dim>\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<depth_to_space_test_params>::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<std::string, InferenceEngine::DataPtr> item = *out.begin();
InferenceEngine::TBlob<float>::Ptr output;
output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
output->allocate();
outputBlobs[item.first] = output;
// Output Reference
InferenceEngine::TBlob<float> dst_ref(item.second->getTensorDesc());
dst_ref.allocate();
// Input Data
InferenceEngine::Blob::Ptr src;
src = InferenceEngine::make_shared_blob<float>({ InferenceEngine::Precision::FP32, p.out_shape, InferenceEngine::TensorDesc::getLayoutByDims(p.out_shape) });
src->allocate();
if (p.reference.size())
memcpy(static_cast<float*>(src->buffer()), &p.reference[0], sizeof(float)*p.reference.size());
auto * srcPtr = dynamic_cast<InferenceEngine::TBlob<float>*>(src.get());
if (srcPtr == nullptr)
FAIL() << "Cannot cast blob to TBlob<float>.";
// 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<std::string, InferenceEngine::Blob::Ptr>("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<depth_to_space_test_params> {
std::string model_t = R"V0G0N(
<net Name="DepthToSpaceToDepth_net" version="2" precision="FP32" batch="1">
<layers>
<layer name="input" type="Input" precision="FP32" id="1">
<output>
<port id="1">
_IN_
</port>
</output>s
</layer>
<layer name="intermediate" id="2" type="DepthToSpace" precision="FP32">
<data block_size="_BS_"/>
<input>
<port id="1">
_IN_
</port>
</input>
<output>
<port id="2">
_OUT_
</port>
</output>
</layer>
<layer name="output" id="3" type="SpaceToDepth" precision="FP32">
<data block_size="_BS_"/>
<input>
<port id="1">
_OUT_
</port>
</input>
<output>
<port id="2">
_IN_
</port>
</output>
</layer>
</layers>
<edges>
<edge from-layer="1" from-port="1" to-layer="2" to-port="1"/>
<edge from-layer="2" from-port="2" to-layer="3" to-port="1"/>
</edges>
</net>
)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 += "<dim>";
in_shape += std::to_string(p.in_shape[i]) + "</dim>\n";
}
for (size_t i = 0; i < p.out_shape.size(); i++) {
out_shape += "<dim>";
out_shape += std::to_string(p.out_shape[i]) + "</dim>\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<depth_to_space_test_params>::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<std::string, InferenceEngine::DataPtr> item = *out.begin();
InferenceEngine::TBlob<float>::Ptr output;
output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
output->allocate();
outputBlobs[item.first] = output;
// Input Data
InferenceEngine::Blob::Ptr src;
src = InferenceEngine::make_shared_blob<float>({ 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<InferenceEngine::TBlob<float>*>(src.get());
if (srcPtr == nullptr)
FAIL() << "Cannot cast blob to TBlob<float>.";
InferenceEngine::BlobMap srcs;
srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("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<float> 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 },{} }
));