我已经使用(Tensorflow)Python API重新训练了Inception-v3模型,并通过修改tensorflow/tensorflow/examples/image_retraining/retrain.py保存了一个独立的.pb格式的图。修改包括在分类层之前添加了一个dropout层:
def nn_layer(input_tensor, input_dim, output_dim, layer_name, activation_name='activation', act=tf.nn.softmax):
# 使用名称范围确保图中层的逻辑分组
with tf.name_scope(layer_name):
# 这个变量将保存层的权重状态
with tf.name_scope('weights'):
weights = weight_variable([input_dim, output_dim])
variable_summaries(weights, layer_name + '/weights')
with tf.name_scope('dropout'):
keep_prob = tf.placeholder(tf.float32)
tf.scalar_summary('dropout_keep_probability', keep_prob)
drop = tf.nn.dropout(input_tensor, keep_prob)
variable_summaries(drop, layer_name + '/dropout')
with tf.name_scope('biases'):
biases = bias_variable([output_dim])
variable_summaries(biases, layer_name + '/biases')
preactivate = tf.matmul(drop, weights) + biases
tf.histogram_summary(layer_name + '/pre_activations', preactivate)
with tf.name_scope(activation_name):
activations = act(preactivate)
tf.histogram_summary(layer_name + '/activations', activations)
return preactivate, activations, keep_prob
在Python中生成预测的代码如下:
softmax_tensor = sess.graph.get_tensor_by_name('final_layer/final_result/Softmax:0')
predictions = sess.run(softmax_tensor, { 'DecodeJpeg/contents:0':image_data, 'final_layer/dropout/Placeholder:0': 1.})
相应的C++代码如下:
string input_layer = "Mul";
string output_layer = "final_layer/dropout/Placeholder:0";
Status run_status = session->Run({{input_layer, resized_tensor}}, {output_layer}, {}, &outputs);
C++代码最终出现了以下错误信息:
Running model failed: Invalid argument: You must feed a value for placeholder tensor 'final_layer/dropout/Placeholder'
为了消除上述错误,我应该如何修改C++代码?换句话说,如何在C++代码中像在Python代码中一样更改占位符的值?我已经在这个问题上卡了很多天了,任何帮助都将不胜感激。
回答:
你的C++代码并不是Python代码的对应部分。
在Python中,你有:
softmax_tensor = sess.graph.get_tensor_by_name('final_layer/final_result/Softmax:0')
predictions = sess.run(softmax_tensor, { 'DecodeJpeg/contents:0':image_data, 'final_layer/dropout/Placeholder:0': 1.})
因此,你的feed_dict
是{ 'DecodeJpeg/contents:0':image_data, 'final_layer/dropout/Placeholder:0': 1.}
。
这意味着:用image_data
覆盖DecodeJpeg/contents:0
的值,并用1.
覆盖final_layer/dropout/Placeholder:0
的值。
然而,在C++中,你有:
Status run_status = session->Run({{input_layer, resized_tensor}}, {output_layer}, {}, &outputs);
这意味着你的feed_dict
等同于第一个输入参数,即:
{{input_layer, resized_tensor}}
这意味着:用resized_tensor
覆盖input_layer
的值。
第一个问题是你试图覆盖节点Mul
而不是节点DecodeJpeg/contents:0
。
此外,还缺少对占位符的覆盖。
然而,你的C++代码中有些混乱,因为你将output_tensor
称为实际上是placeholder
的东西。
TL;DR
你的Python代码的对应C++代码应该是这样的:
Status run_status = session->Run({
{"DecodeJpeg/contents", resized_tensor},
{"final_layer/dropout/Placeholder", 1f}},
{"final_layer/final_result/Softmax"}, {}, &outputs);
这意味着:
用resize_tensor
覆盖节点DecodeJpeg/contents
的值。
用1覆盖节点final_layer/dropout/Placeholder
的值。
获取节点final_layer/final_result/Softmax
的值。
将结果放入outputs
中