Fixed mean image support for IR v10 (#1926)

* Fixed mean image support for IR v10

* Fixed comments
This commit is contained in:
Ilya Churaev 2020-08-26 20:45:54 +03:00 committed by GitHub
parent 7859aab4b0
commit a072c3b7b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 225 additions and 1 deletions

View File

@ -196,7 +196,135 @@ std::shared_ptr<ICNNNetwork> V10Parser::parse(const pugi::xml_node& root, std::i
result_nodes[0]->add_control_dependency(assign);
}
}
return CNNNetwork(function);
CNNNetwork net(function);
parsePreProcess(net, root, binStream);
return net;
}
void V10Parser::parsePreProcess(CNNNetwork& network, const pugi::xml_node& root, std::istream& binStream) {
/*
<pre-process mean-precision="FP32">
<channel id = 0>
<mean offset = "121930449" size = "51529" / > // in case of array ref to the .bin file
</channel>
</pre-process>
*/
auto ppNode = root.child("pre-process");
if (ppNode.empty()) {
return;
}
// find out to what input this belongs to
std::string inputName;
InputInfo::Ptr preProcessInput;
inputName = GetStrAttr(ppNode, "reference-layer-name", "");
inputName = ngraph::trim(inputName);
if (inputName.empty()) {
// fallback (old format), look for the picture in the inputs
InputsDataMap inputs = network.getInputsInfo();
if (inputs.empty()) THROW_IE_EXCEPTION << "network has no input";
for (auto i : inputs) {
if (i.second->getTensorDesc().getDims().size() == 4) {
preProcessInput = i.second;
break;
}
}
if (!preProcessInput) {
preProcessInput = inputs.begin()->second;
}
inputName = preProcessInput->name();
} else {
preProcessInput = network.getInputsInfo()[inputName];
if (!preProcessInput)
THROW_IE_EXCEPTION << "pre-process name ref '" << inputName << "' refers to un-existing input";
}
// dims vector without batch size
SizeVector inputDims = preProcessInput->getTensorDesc().getDims();
size_t noOfChannels = 0, width = 0, height = 0;
if (inputDims.size() < 2) {
THROW_IE_EXCEPTION << "network did not define input dimensions properly";
} else if (inputDims.size() == 2) { // NC
noOfChannels = inputDims[1];
width = inputDims[1];
height = inputDims[0];
} else if (inputDims.size() == 3) {
width = inputDims[2];
height = inputDims[1];
noOfChannels = inputDims[0];
} else if (inputDims.size() == 4) {
width = inputDims[3];
height = inputDims[2];
noOfChannels = inputDims[1];
} else if (inputDims.size() == 5) {
width = inputDims[4];
height = inputDims[3];
noOfChannels = inputDims[2];
}
PreProcessInfo& pp = preProcessInput->getPreProcess();
pp.init(noOfChannels);
auto meanSegmentPrecision = GetPrecisionAttr(ppNode, "mean-precision", Precision::UNSPECIFIED);
if (!meanSegmentPrecision || meanSegmentPrecision == Precision::MIXED)
THROW_IE_EXCEPTION << "mean blob defined without specifying precision.";
ResponseDesc resp;
InferenceEngine::PreProcessChannel::Ptr preProcessChannel;
int lastChanNo = -1;
std::unordered_set<int> idsForMeanImage;
FOREACH_CHILD(chan, ppNode, "channel") {
int chanNo = GetIntAttr(chan, "id", lastChanNo + 1);
if (chanNo >= static_cast<int>(noOfChannels) || chanNo < 0) {
THROW_IE_EXCEPTION << "Pre-process channel id invalid: " << chanNo;
}
lastChanNo = chanNo;
preProcessChannel = pp[chanNo];
auto meanNode = chan.child("mean");
if (!meanNode.empty()) {
if (!meanNode.attribute("size")) {
THROW_IE_EXCEPTION << "mean should have the attribute: size";
}
if (meanNode.attribute("size")) {
idsForMeanImage.insert(chanNo);
size_t size = static_cast<size_t>(GetIntAttr(meanNode, "size"));
size_t offset = static_cast<size_t>(GetIntAttr(meanNode, "offset"));
if (width * height * meanSegmentPrecision.size() != size) {
THROW_IE_EXCEPTION << "mean blob size mismatch expected input, got: " << size
<< " extpecting " << width << " x " << height << " x "
<< meanSegmentPrecision.size();
}
preProcessChannel->meanData = make_blob_with_precision(TensorDesc(meanSegmentPrecision, {height, width}, Layout::HW));
preProcessChannel->meanData->allocate();
auto lockedMem = preProcessChannel->meanData->buffer();
char* data = lockedMem.as<char *>();
binStream.seekg(offset, std::ios::beg);
binStream.read(data, size);
}
}
}
if (idsForMeanImage.size() == noOfChannels) {
pp.setVariant(MEAN_IMAGE);
} else if (idsForMeanImage.size() == 0) {
pp.setVariant(NONE);
} else {
std::string validMeanImageIds = "";
for (auto id : idsForMeanImage) {
validMeanImageIds += std::to_string(id) + " ";
}
THROW_IE_EXCEPTION << "mean is not provided for all channels\n"
"Provided mean image for: "
<< validMeanImageIds;
}
}
V10Parser::GenericLayerParams V10Parser::parseGenericParams(const pugi::xml_node& node) {

View File

@ -7,6 +7,7 @@
#ifdef IR_READER_V10
# include <ngraph/node.hpp>
# include <legacy/ie_ngraph_utils.hpp>
# include <cpp/ie_cnn_network.h>
#endif // IR_READER_V10
#include <ie_blob.h>
@ -169,6 +170,7 @@ private:
std::istream& binStream, const GenericLayerParams& params);
GenericLayerParams parseGenericParams(const pugi::xml_node& node);
void parsePreProcess(CNNNetwork& network, const pugi::xml_node& root, std::istream& binStream);
std::map<std::string, DataPtr> portsToData;
std::map<std::string, GenericLayerParams> layersParseInfo;

View File

@ -461,6 +461,100 @@ TEST(CNNNGraphImplTests, ReadFromCNNNetReader) {
ASSERT_EQ(3, network.layerCount());
}
TEST(CNNNGraphImplTests, ReadMeanImageFromCNNNetReader) {
std::string model = R"V0G0N(
<net name="Activation" version="10">
<pre-process mean-precision="FP32" reference-layer-name="data">
<channel id="0">
<mean offset="0" size="1936"/>
</channel>
<channel id="1">
<mean offset="1936" size="1936"/>
</channel>
<channel id="2">
<mean offset="3872" size="1936"/>
</channel>
</pre-process>
<layers>
<layer name="data" type="Parameter" id="0" version="opset1">
<data shape="1,3,22,22" element_type="f32"/>
<output>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</output>
</layer>
<layer name="activation" id="1" type="ReLU" version="opset1">
<input>
<port id="1" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</input>
<output>
<port id="2" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</output>
</layer>
<layer name="output" type="Result" id="2" version="opset1">
<input>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</input>
</layer>
</layers>
<edges>
<edge from-layer="0" from-port="0" to-layer="1" to-port="1"/>
<edge from-layer="1" from-port="2" to-layer="2" to-port="0"/>
</edges>
</net>
)V0G0N";
InferenceEngine::Core core;
size_t hwSize = 22*22;
size_t dataSize = hwSize*3;
Blob::Ptr data = make_shared_blob<float>(TensorDesc(Precision::FP32, {dataSize}, Layout::C));
data->allocate();
{
auto lockData = data->buffer();
float *dataPtr = lockData.as<float*>();
for (size_t i = 0; i < dataSize; ++i) {
dataPtr[i] = i;
}
}
CNNNetwork network = core.ReadNetwork(model, data);
ASSERT_EQ(3, network.layerCount());
auto inputInfo = network.getInputsInfo().begin()->second;
ASSERT_NE(inputInfo, nullptr);
auto preProc = inputInfo->getPreProcess();
ASSERT_EQ(3, preProc.getNumberOfChannels());
ASSERT_EQ(preProc.getMeanVariant(), MeanVariant::MEAN_IMAGE);
for (size_t i = 0; i < preProc.getNumberOfChannels(); i++) {
auto chMeanImg = preProc[i];
ASSERT_NE(chMeanImg, nullptr);
ASSERT_NE(chMeanImg->meanData, nullptr);
auto lockData = chMeanImg->meanData->cbuffer();
auto *dataPtr = lockData.as<const float*>();
for (size_t j = 0; j < hwSize; j++) {
ASSERT_EQ(dataPtr[j], hwSize*i + j);
}
}
}
TEST(CNNNGraphImplTests, CanChangeInputPrecision) {
std::shared_ptr<ngraph::Function> ngraph;
{