TensorFlow C+的推理错误+;关于iOS:“;无效参数:在运行()之前未使用图形创建会话&引用; 我试图用TensorFlow的C++ API在iOS上运行模型。模型是一个SavedModel另存为.pb文件。但是,调用Session::Run()会导致以下错误:
“无效参数:在运行()之前未使用图形创建会话!” 在Python中,我可以使用以下代码成功地在模型上运行推理:TensorFlow C+的推理错误+;关于iOS:“;无效参数:在运行()之前未使用图形创建会话&引用; 我试图用TensorFlow的C++ API在iOS上运行模型。模型是一个SavedModel另存为.pb文件。但是,调用Session::Run()会导致以下错误:,c++,ios,tensorflow,C++,Ios,Tensorflow,“无效参数:在运行()之前未使用图形创建会话!” 在Python中,我可以使用以下代码成功地在模型上运行推理: with tf.Session() as sess: tf.saved_model.loader.load(sess, ['serve'], '/path/to/model/export') result = sess.run(['OutputTensorA:0', 'OutputTensorB:0'], feed_dict={ 'InputTensor
with tf.Session() as sess:
tf.saved_model.loader.load(sess, ['serve'], '/path/to/model/export')
result = sess.run(['OutputTensorA:0', 'OutputTensorB:0'], feed_dict={
'InputTensorA:0': np.array([5000.00] * 1000).reshape(1, 1000),
'InputTensorB:0': np.array([300.00] * 1000).reshape(1, 1000)
})
print(result[0])
print(result[1])
在iOS上C++,我尝试模仿这个工作片段如下:
tensorflow::Input::Initializer input_a(5000.00, tensorflow::TensorShape({1, 1000}));
tensorflow::Input::Initializer input_b(300.00, tensorflow::TensorShape({1, 1000}));
tensorflow::Session* session_pointer = nullptr;
tensorflow::SessionOptions options;
tensorflow::Status session_status = tensorflow::NewSession(options, &session_pointer);
std::cout << session_status.ToString() << std::endl; // prints OK
std::unique_ptr<tensorflow::Session> session(session_pointer);
tensorflow::GraphDef model_graph;
NSString* model_path = FilePathForResourceName(@"saved_model", @"pb");
PortableReadFileToProto([model_path UTF8String], &model_graph);
tensorflow::Status session_init = session->Create(model_graph);
std::cout << session_init.ToString() << std::endl; // prints OK
std::vector<tensorflow::Tensor> outputs;
tensorflow::Status session_run = session->Run({{"InputTensorA:0", input_a.tensor}, {"InputTensorB:0", input_b.tensor}}, {"OutputTensorA:0", "OutputTensorB:0"}, {}, &outputs);
std::cout << session_run.ToString() << std::endl; // Invalid argument: Session was not created with a graph before Run()!
tensorflow::Input::初始值设定项Input_a(5000.00,tensorflow::TensorShape({11000}));
tensorflow::Input::初始值设定项Input_b(300.00,tensorflow::TensorShape({1,1000}));
tensorflow::Session*Session_pointer=nullptr;
tensorflow::SessionOptions选项;
tensorflow::Status session\u Status=tensorflow::NewSession(选项和会话指针);
STD::CUT这里的主要问题是,将图形导出到Python中,然后以C++的形式读取它。虽然两者都有一个
.pb
扩展名并且相似,但它们并不等同
发生的情况是,您正在使用PortableReadFileToProto()
读取SavedModel
,但它失败了,留下一个指向GraphDef
对象的空指针(model\u graph
)。因此,在执行了PortableReadFileToProto()
之后,model_graph
仍然是一个空的但有效的,GraphDef
,这就是为什么错误显示在运行()之前没有使用图形创建会话的原因<代码>会话->创建()成功,因为您成功创建了一个带有空图的会话
检查PortableReadFileToProto()是否失败的方法是检查其返回值。它返回一个布尔值,如果在图形中读取失败,该布尔值将为0。如果希望在此处获得描述性错误,请使用。另一种判断读取图形是否失败的方法是检查model\u graph.node\u size()
的值。如果该值为0,则您有一个空图形,并且在中读取它失败
虽然您可以使用TensorFlow的C API通过和对SavedModel
执行推断,但推荐的方法是使用导出图形到冻结模型,或使用写入GraphDef
。我将用使用tf.train.write_graph()
导出的模型演示成功的推理:
在Python中:
# Build graph, call it g
g = tf.Graph()
with g.as_default():
input_tensor_a = tf.placeholder(dtype=tf.int32, name="InputTensorA")
input_tensor_b = tf.placeholder(dtype=tf.int32, name="InputTensorB")
output_tensor_a = tf.stack([input_tensor_a], name="OutputTensorA")
output_tensor_b = tf.stack([input_tensor_b], name="OutputTensorB")
# Save graph g
with tf.Session(graph=g) as sess:
sess.run(tf.global_variables_initializer())
tf.train.write_graph(
graph_or_graph_def=sess.graph_def,
logdir='/path/to/export',
name='saved_model.pb',
as_text=False
)
C++(XCODEL):
使用名称空间tensorflow;
使用名称空间std;
NSMutableArray*预测=[NSMutableArray];
Input::初始化器Input_tensor_a(1,TensorShape({1}));
Input::初始化器Input_tensor_b(2,TensorShape({1}));
会话选项;
Session*Session_指针=nullptr;
状态会话\状态=新闻会话(选项和会话\指针);
唯一的会话(会话指针);
GraphDef模型图;
string model_path=string([FilePathForResourceName(@“saved_model”,“pb”)UTF8String]);
状态加载\图形=ReadBinaryProto(Env::Default()、模型\路径和模型\图形);
状态会话\初始化=会话->创建(模型\图形);
除了上面非常全面的解释之外,还有一个补充:
@jshapy8说得对,“您必须找到包含REGISTER_OP(“YourOperation”)的.cc并将其添加到tf_OP_files.txt中”,有一个过程可以稍微简化这一点:
## build the print_selective_register_header tool. Run from tensorflow root
bazel build tensorflow/python/tools:print_selective_registration_header
bazel-bin/tensorflow/python/tools/print_selective_registration_header \
--graphs=<path to your frozen model file here>/model_frozen.pb > ops_to_register.h
但是,您可以根据自己的需要向makefile传递很多信息,我发现以下是您的最佳选择:
make -f tensorflow/contrib/makefile/Makefile \
TARGET=IOS IOS_ARCH=ARM64,x86_64 OPTFLAGS="-O3 -DANDROID_TYPES=ANDROID_TYPES_FULL -DSELECTIVE_REGISTRATION -DSUPPORT_SELECTIVE_REGISTRATION"
特别是,您在这里告诉它只编译5种体系结构中的两种,以加快编译时间(完整列表是:i386 x86_64 armv7 armv7s arm64,显然需要更长的时间)-IOS_ARCH=arm64,x86_64-然后您告诉它不要编译ANDROID_类型的_SLIM(这将给您带来上面提到的浮点/整数转换问题)最后,您告诉它提取所有必需的ops内核文件,并将它们包含在生成过程中
更新。我不知道为什么昨天这对我不起作用,但这可能是一种更干净、更安全的方法:
build_all_ios.sh OPTFLAGS="-O3 -DANDROID_TYPES=ANDROID_TYPES_FULL -DSELECTIVE_REGISTRATION -DSUPPORT_SELECTIVE_REGISTRATION"
如果要加快速度,请编辑/Makefile目录中的compile_ios_tensorflow.sh。查找以下行:
BUILD_TARGET="i386 x86_64 armv7 armv7s arm64"
并将其更改为:
BUILD_TARGET="x86_64 arm64"
BUILD_TARGET="i386 x86_64 armv7 armv7s arm64"
BUILD_TARGET="x86_64 arm64"