我在Keras训练我的模型,然后使用C ++将其转换为tensorflow模型进行推理(我没有量化)。我在C ++中的推理代码很简单。
我直接从文件中读取图像。我使用以下函数执行Decode png,调整大小和规范化操作。
static Status ReadFile(Env *oEnv, const string &sFileName, Tensor *output)
{
uint64 nFileSize = 0;
TF_RETURN_IF_ERROR(oEnv->GetFileSize(sFileName, &nFileSize));
string oFile;
oFile.resize(nFileSize);
std::unique_ptr<RandomAccessFile> oFileAccess;
TF_RETURN_IF_ERROR(oEnv->NewRandomAccessFile(sFileName, &oFileAccess));
StringPiece oData;
TF_RETURN_IF_ERROR(oFileAccess->Read(0, nFileSize, &oData, &(oFile)[0]));
output->scalar<string>()() = oData.ToString();
return Status::OK();
}
//Reads a PNG image and converts it to a tensor of specified size.
Status ReadImageFromFile(const string &sFileName, const int nWidth, const int nHeight, const float fMean, const float fScale, std::vector<Tensor> *oTensor)
{
Tensor oTInput(DT_STRING, TensorShape());
TF_RETURN_IF_ERROR(ReadFile(Env::Default(), sFileName, &oTInput));
auto oTRoot = Scope::NewRootScope();
auto oInput = ops::Placeholder(oTRoot.WithOpName("input"), DT_STRING);
std::vector<std::pair<string, Tensor>> oInputs = { {"input",oTInput} };
Output oOpImgRead = ops::DecodePng(oTRoot.WithOpName("png_file"), oInput, ops::DecodePng::Channels(3));
auto oTFloatConv = ops::Cast(oTRoot.WithOpName("float_conv"), oOpImgRead, DT_FLOAT);
auto oDimExpand = ops::ExpandDims(oTRoot, oTFloatConv, 0);
auto oResize = ops::ResizeBilinear(oTRoot, oDimExpand, ops::Const(oTRoot.WithOpName("size"), { nHeight, nWidth }));
auto oMeanSub = ops::Sub(oTRoot, oResize, { fMean });
auto oScale = ops::Div(oTRoot.WithOpName("output"), oMeanSub, { fScale });
GraphDef oGraph;
TF_RETURN_IF_ERROR(oTRoot.ToGraphDef(&oGraph));
Session *oSess;
NewSession(SessionOptions(), &oSess);
TF_RETURN_IF_ERROR(oSess->Create(oGraph));
TF_RETURN_IF_ERROR(oSess->Run({ oInputs }, { "output" }, {}, oTensor));
return Status::OK();
}
然后我使用以下代码进行推理。
GraphDef oGraphDef;
oStatus = ReadBinaryProto(Env::Default(), "models/graph.pb", &oGraphDef);
if (!oStatus.ok())
{
std::cout << oStatus.ToString() << std::endl;
getchar();
return -1;
}
std::cout << "Graph read\n";
std::vector<Tensor> oInputTensors;
oStatus = ReadImageFromFile("temp.png", 224, 224, 127.5, 255.0, &oInputTensors);
if (!oStatus.ok())
{
std::cout << oStatus.ToString() << std::endl;
getchar();
return -1;
}
std::cout << "Input image read\n";
//Create Session
Session *oSess;
oStatus = NewSession(SessionOptions(), &oSess);
if (!oStatus.ok())
{
std::cout << oStatus.ToString() << std::endl;
getchar();
return -1;
}
oStatus = oSess->Create(oGraphDef);
if (!oStatus.ok())
{
std::cout << oStatus.ToString() << std::endl;
getchar();
return -1;
}
std::vector<Tensor> oOutputs;
oStatus = oSess->Run({ { "input_input",oInputTensors[0] } }, { "activation_output/Relu" }, {}, &oOutputs);
if (!oStatus.ok())
{
std::cout << oStatus.ToString() << std::endl;
getchar();
return -1;
}
我错过了什么吗?
答案 0 :(得分:2)
我猜这个错误不是来自图表的执行,而是来自你对图像进行的预处理。对我来说候选人是ops::ResizeBilinear
,每个库的双线性插值实现略有不同,所以你可能会想到张量流和keras之间的差异。
尝试使用两个系统中正确尺寸的图像来评估差异,这样就可以避免插值。作为一个例子,我不得不重新实现我自己的C ++插值,以尽可能接近我在python中使用的插值。