Tensorflow C ++推断结果与Keras推理略有不同

时间:2018-04-18 13:58:41

标签: python c++ tensorflow keras

我在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;
}

我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

我猜这个错误不是来自图表的执行,而是来自你对图像进行的预处理。对我来说候选人是ops::ResizeBilinear,每个库的双线性插值实现略有不同,所以你可能会想到张量流和keras之间的差异。

尝试使用两个系统中正确尺寸的图像来评估差异,这样就可以避免插值。作为一个例子,我不得不重新实现我自己的C ++插值,以尽可能接近我在python中使用的插值。