草庐IT

c++ - iOS : "Invalid argument: Session was not created with a graph before Run()!" 上的 TensorFlow C++ 推理错误

coder 2023-09-28 原文

我正在尝试使用 TensorFlow 的 C++ API 在 iOS 上运行我的模型。型号是SavedModel保存为 .pb文件。但是,请调用 Session::Run()导致错误:

"Invalid argument: Session was not created with a graph before Run()!"



在 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={
        '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()!

方法 FilePathForResourceNamePortableReadFileToProto取自 TensorFlow iOS 示例 here .

问题是什么?我注意到无论模型有多简单( see my issue report on GitHub )都会发生这种情况,这意味着问题不在于模型的细节。

最佳答案

这里的主要问题是您将图形导出到 SavedModel 在 Python 中,然后将其作为 GraphDef 读入在 C++ 中。虽然两者都有 .pb扩展和相似,它们不等价。

正在发生的事情是您正在阅读 SavedModelPortableReadFileToProto()它失败了,留下一个空指针( model_graph )到 GraphDef目的。所以在执行 PortableReadFileToProto() 之后, model_graph仍然是空的,但有效,GraphDef ,这就是为什么错误说 Session 不是在 Run() 之前用图形创建的。 session->Create()成功是因为您成功地创建了一个带有空图的 session 。

检查是否PortableReadFileToProto()的方法失败是检查其返回值。它返回一个 bool 值,如果读取图形失败,它将为 0。如果您想在此处获得描述性错误,请使用 ReadBinaryProto() .判断读取图形是否失败的另一种方法是检查 model_graph.node_size() 的值。 .如果这是 0,那么您有一个空图并且读取它失败。

虽然您可以使用 TensorFlow 的 C API 在 SavedModel 上执行推理通过使用 TF_LoadSessionFromSavedModel() TF_SessionRun() ,推荐的方法是使用 freeze_graph.py 将图形导出到卡住模型。或写信给 GraphDef使用 tf.train.write_graph() .我将演示使用 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++ (Xcode) 中:
using namespace tensorflow;
using namespace std;

NSMutableArray* predictions = [NSMutableArray array];

Input::Initializer input_tensor_a(1, TensorShape({1}));
Input::Initializer input_tensor_b(2, TensorShape({1}));

SessionOptions options;
Session* session_pointer = nullptr;
Status session_status = NewSession(options, &session_pointer);
unique_ptr<Session> session(session_pointer);

GraphDef model_graph;
string model_path = string([FilePathForResourceName(@"saved_model", @"pb") UTF8String]);

Status load_graph = ReadBinaryProto(Env::Default(), model_path, &model_graph);

Status session_init = session->Create(model_graph);

cout << "Session creation Status: " << session_init.ToString() << endl;
cout << "Number of nodes in model_graph: " << model_graph.node_size() << endl;
cout << "Load graph Status: " << load_graph.ToString() << endl;

vector<pair<string, Tensor>> feed_dict = {
    {"InputTensorA:0", input_tensor_a.tensor},
    {"InputTensorB:0", input_tensor_b.tensor}
};

vector<Tensor> outputs;
Status session_run = session->Run(feed_dict, {"OutputTensorA:0", "OutputTensorB:0"}, {}, &outputs);

[predictions addObject:outputs[0].scalar<int>()];
[predictions addObject:outputs[1].scalar<int>()];

Status session_close = session->Close();

这种通用方法可行,但您可能会遇到构建的 TensorFlow 库中缺少所需操作的问题,因此推理仍然会失败。为了解决这个问题,首先确保你已经构建了最新的 TensorFlow 1.3 通过在您的机器上克隆 repo 并运行 tensorflow/contrib/makefile/build_all_ios.sh 从根tensorflow-1.3.0目录。如果您使用 TensorFlow-experimental ,推理不太可能适用于自定义的非固定模型。 Pod 喜欢这些例子。一旦你使用 build_all_ios.sh 构建了一个静态库,您需要在您的 .xcconfig 中链接它按照说明操作 here .

一旦您成功地将使用 makefile 构建的静态库与 Xcode 链接起来,您可能仍然会遇到阻止推理的错误。虽然您将获得的实际错误取决于您的实现,但您将收到分为两种不同形式的错误:
  • OpKernel ('op: "[operation]" device_type: "CPU"') for unknown op: [operation]

  • No OpKernel was registered to support Op '[operation]' with these attrs. Registered devices: [CPU], Registered kernels: [...]


  • 错误 #1 表示 .cc文件来自 tensorflow/core/opstensorflow/core/kernels对应的操作(或密切相关的操作)不在 tf_op_files.txt 中文件在 tensorflow/contrib/makefile .您必须找到 .cc包含 REGISTER_OP("YourOperation")并将其添加到 tf_op_files.txt .您必须通过运行 tensorflow/contrib/makefile/build_all_ios.sh 来重建再次。

    错误 #2 意味着 .cc相应操作的文件在您的 tf_op_files.txt 中文件,但是您为操作提供了它 (a) 不支持或 (b) 被剥离以减小构建大小的数据类型。

    一个“问题”是,如果您使用 tf.float64在你的模型的实现中,这被导出为 TF_DOUBLE在您的 .pb文件,大多数操作不支持此功能。使用 tf.float32代替 tf.float64然后使用 tf.train.write_graph() 重新保存您的模型.

    如果在检查为操作提供了正确的数据类型后仍然收到错误 #2,则需要删除 __ANDROID_TYPES_SLIM__在位于 tensorflow/contrib/makefile 的 makefile 中或替换为 __ANDROID_TYPES_FULL__然后重建。

    在通过错误 #1 和 #2 之后,您可能会成功推理。

    关于c++ - iOS : "Invalid argument: Session was not created with a graph before Run()!" 上的 TensorFlow C++ 推理错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46201109/

    有关c++ - iOS : "Invalid argument: Session was not created with a graph before Run()!" 上的 TensorFlow C++ 推理错误的更多相关文章

    1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

      我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

    3. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

      为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

    4. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    5. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

      我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

    6. ruby-on-rails - openshift 上的 rails 控制台 - 2

      我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

    7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

      我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

    8. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

      我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

    9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

      我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

    10. ruby - 如何验证 IO.copy_stream 是否成功 - 2

      这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

    随机推荐