【问题标题】:Running inference with a loaded tensorflow model in C++在 C++ 中使用加载的张量流模型运行推理
【发布时间】:2018-11-27 21:51:50
【问题描述】:

我的这个例子的 tensorflow 模型很简单,并且已经成功加载。我的问题是,要运行推理,我应该通过 tf::Session 传递什么?如何创建 here 提到的 feedDict 以及我的“outputOps”是什么?

这是python中的模型:

model = tf.keras.Sequential([
tf.keras.layers.Convolution2D(filters, (5, 5), input_shape=(BoardDepth, BoardLength, BoardLength), data_format='channels_first', name='Input'),
tf.keras.layers.Activation('relu', name='Relu'),
tf.keras.layers.MaxPooling2D(pool_size=(2,2), name='Pool'),
tf.keras.layers.Flatten(name="Flatten"),
tf.keras.layers.Dense(BoardSize, activation='softmax', name='Output'),
])

optimizer = tf.train.AdamOptimizer(learning_rate=0.0018)

model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) 

这是用于训练模型的方法,该模型使用生成器来输入图像:

earlyExit = keras.callbacks.EarlyStopping(monitor='val_acc', min_delta=0, patience=0)

# Train the model
history = model.fit_generator(generator=gen.generator(),
                steps_per_epoch=gen.stepsPerEpoch(),
                validation_data=valGen.generator(),
                validation_steps=valGen.stepsPerEpoch(),
                epochs=numEpochs, 
                verbose=2, workers=1, callbacks=[earlyExit])

这是用于保存模型的方法:

K.set_learning_phase(0)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver(tf.trainable_variables())
    saver.save(sess, './models/test/latestModel')

如果您没有按照上面的链接进行推断,则应该通过以下方式完成:

// and run the inference to your liking
auto feedDict = ...
auto outputOps = ...
std::vector<tensorflow::Tensor> outputTensors;
status = session->Run(feedDict, outputOps, {}, &outputTensors);

我尝试按照示例 here 进行操作,但似乎无法弄清楚我需要作为 outputOps 传递什么。我只需要传递输出节点的名称,还是需要传递模型中的每一个操作?到目前为止,我尝试过的不同配置都没有奏效。

到目前为止,我的代码如下所示:

auto shape = tf::TensorShape({ BoardDepth, BoardSize, BoardSize});

// Placeholder until we're using actual input data
float inData[inputSize] = { 0.0 };

tf::Tensor input(tf::DT_FLOAT, shape);
std::copy_n(inData, inputSize, input.flat<float>().data());

std::vector<std::pair<std::string, tf::Tensor>> inputs = {
    { "Input/Conv2D", input },
};

std::vector<std::string> outOps = { "Output/bias:0"};

std::vector<tf::Tensor> outputs;

status = session->Run(inputs, outOps, {}, &outputs);

输入/输出名称只是设置为我能找到的不会引发错误的名称。我真的不知道我应该将它们设置为什么,以便模型能够按照训练的方式运行。

【问题讨论】:

  • 你的 tf.placeholder 在哪里? keras.compile 在哪里?本质上,您只需要传递输出张量名称。
  • 我需要 tf.placeholder 做什么?我在上面的python代码中添加了keras的编译和用于保存模型的代码。我尝试设置 outOps = {"Output"} (最后一层的名称),但这不起作用并给出错误“FetchOutputs node Output: not found”
  • 您在此处显示的 C++ 代码对我来说看起来是正确的。至少它和我使用的差不多。到目前为止,我看到的唯一区别是,我没有将“:0”添加到任何节点名称中。您应该作为输出节点移交的节点绝对只是最后一个。您确定您的图表已正确加载吗?也许将图形另存为文本会有所帮助,因此您可以检查它是否保存了您的期望,并搜索输出节点的确切名称。您可以使用 tf.train.write_graph(..., as_text=True) 来做到这一点。
  • 必须有某种方法可以将数据输入图表。最简单的方法是使用tf.placeholder。诀窍就是使用whatever_tensor.name 获取张量名称并在feed_dictoutput 中使用它
  • @Patwie,现在我正在使用 model.fit_generator() 将数据输入模型并且没有 tf.placeholder。有没有办法使用它,或者找到输入张量的名称?

标签: python c++ tensorflow


【解决方案1】:

将输出张量名称打印为 Patwie 的答案显示了如何解决一半的问题。 keras 的输入张量名称似乎是您的第一层名称 + _input,所以在我的情况下,我的输入名称是 Input_input。

【讨论】:

    【解决方案2】:

    它的工作方式与存储库中给定的example.py 完全相同。

    在python中你写:

    import tensorflow as tf
    import numpy as np
    sess = tf.Session()
    
    from keras import backend as K
    K.set_session(sess)
    
    img = tf.placeholder(tf.float32, shape=(None, 2), name='input_plhdr')
    
    model = tf.keras.Sequential([
        tf.keras.layers.Dense(10, activation='relu', name='Intermediate'),
        tf.keras.layers.Dense(2, activation='softmax', name='Output'),
    ])
    
    M = model(img)
    print('input', img.name)
    print('output', M.name)
    sess.run(tf.global_variables_initializer())
    print('result', sess.run(M, {img: np.array([[42, 43.]], dtype=np.float32)}))
    
    saver = tf.train.Saver(tf.global_variables())
    saver.save(sess, './exported/my_model')
    tf.train.write_graph(sess.graph, '.', "./exported/graph.pb", as_text=False)
    

    print('input', img.name)  # ('input', u'input_plhdr:0')
    print('output', M.name)   # ('output', u'sequential/Output_1/Softmax:0')
    

    告诉你输入和输出的名称。适配inference_cc.cc你只需要填写正确的名字:

    // same as in python file
    auto data_ = data.flat<float>().data();
    data_[0] = 42;
    data_[1] = 43;
    
    tensor_dict feed_dict = {
      { "input_plhdr", data },
    };
    
    std::vector<tensorflow::Tensor> outputs;
    TF_CHECK_OK(sess->Run(feed_dict, {"sequential/Output_1/Softmax:0"}, {}, &outputs));
    
    std::cout << "input           " << data.DebugString() << std::endl;
    std::cout << "output          " << outputs[0].DebugString() << std::endl;
    

    在 Python 中我得到

    Using TensorFlow backend.
    ('input', u'input_plhdr:0')
    ('output', u'sequential/Output_1/Softmax:0')
    ('result', array([[1.0000000e+00, 1.8979743e-11]], dtype=float32))
    

    然后 C++ 返回

    input           Tensor<type: float shape: [1,2] values: [42 43]>
    output          Tensor<type: float shape: [1,2] values: [1 1.89797431e-11]>
    

    【讨论】:

    • 所以到目前为止我正在使用 keras.fit_generator() 将图像提供给我的模型,有没有办法可以将 tf.placeholder 与之集成?还是有必要?
    • 为了清晰起见,我已将用于训练模型的当前方法添加到示例代码中。
    • 我对 keras 不是很熟悉。有没有机会创建一个完整的工作要点?
    • 我实际上刚刚找到了 keras 使用的输入张量命名方案。感谢您对输出张量名称的帮助!不幸的是,现在我遇到了 CUDNN 错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 2017-12-15
    • 2021-10-25
    • 2021-03-01
    • 2017-09-22
    • 1970-01-01
    相关资源
    最近更新 更多