簡體   English   中英

針對 TensorFlow C++ API 構建的 Bazel 目標不執行工廠注冊功能

[英]Bazel targets built against TensorFlow C++ API don't execute factory registration functions

我遇到的問題似乎與此處描述的問題相同: https://chromium.googlesource.com/external/github.com/tensorflow/tensorflow/+/v1.4.0/tensorflow/docs_src/mobile/linking_libs。 md#global-constructor-magic

嘗試從您自己的應用程序調用 TensorFlow 時,您可能遇到的最微妙的問題之一是“沒有為給定的 session 選項注冊的工廠沒有注冊”錯誤。 ... TensorFlow 在很多地方都使用了注冊模式:

 class RegisterMul { public: RegisterMul() { global_kernel_registry()->Register(“Mul”, [](){ return new MulKernel() }); } }; RegisterMul g_register_mul;

This sets up a class RegisterMul with a constructor that tells the global kernel registry what function to call when somebody asks it how to create a “Mul” kernel. 然后是 class 的全局 object,因此構造函數應該在任何程序的開頭調用。

定義的全局 object 未被任何其他代碼使用,因此未考慮到這一點設計的鏈接器將決定可以將其刪除。 因此,構造函數永遠不會被調用,並且 class 永遠不會被注冊。

解決方案是強制 linker 不從庫中刪除任何代碼,即使它認為它沒有使用。 在 iOS 上,可以使用-force_load標志完成此步驟,指定庫路徑,在 Linux 上,您需要 --whole --whole-archive 這些說服 linker 在剝離方面不要那么激進,並且應該保留全局變量。

但是,我無法將“打開 Linux 你需要 --whole --whole-archive ”變成實際有效的東西。 我是:

  • 將 TensorFlow 2.2.2 從源代碼編譯成 python 輪
  • 在另一個用 bazel 構建的項目中使用該輪子
  • 通過 bazel 目標暴露該輪子的 C++ API(見下文)
  • 從自定義 C++ 代碼中引用 C++ API 目標

我試過添加:

alwayslink=True,
linkopts = ["-Wl,--whole-archive"],

到上面列表中每個 my 目標的 bazel 目標,並沒有什么不同。 我的車輪目標是:

cc_library(
    name = "c_api",
    # This is the only .so or .so.* in the wheel
    srcs=["//:tensorflow/libtensorflow_framework.so.2"],
    hdrs = glob([
        "tensorflow/include/**/*.h",
        "tensorflow/include/**/*.inc",
        "tensorflow/include/**/Eigen/**/*",
    ]),
    alwayslink=True,
    linkopts = ["-Wl,--whole-archive"],
    includes = [
        "tensorflow/include",
    ],
    visibility = ["//visibility:public"],
    deps = ["@zoox//third_party/cuda:cuda_libs"],
)

以及失敗的實際最終目標:

cc_library(
    name = "tensorflow_wrapper",
    srcs = ["tensorflow_wrapper.cpp"],
    hdrs = ["tensorflow_wrapper.h"],
    tags = ["offline-only"],
    deps = [
        ":utils",
        "//other/stuff:etc",
        # This is the above target for the wheel
        "@pypi__tensorflow_python3_deps//:c_api",
    ],
    alwayslink = 1,
    linkopts = ["-Wl,--whole-archive"],
)

:c_api目標足以讓自定義操作正常工作,失敗的 C++ 代碼仍然可以編譯和運行,只是沒有注冊所需的工廠,因此在需要時失敗。

我需要更改什么才能讓 TensorFlow 使用的注冊模式實際執行?

--whole-archive在這種情況下不起作用。 此標志的全部目的是鏈接static庫(Linux 中的*.a )中的所有內容。 默認情況下,共享庫包含所有編譯后的代碼,所以你不要那個技巧,因為你使用的是*.so文件。

也許問題與tensorflow_wrapper的使用有關。 如果您像這樣從 bazel 鏈接到該庫:

cc_binary(
  name="some_binary",
  src=["main.cpp"],
  deps=["//some/path/to:tensorflow_wrapper"],
)

那么一切都應該正常工作,因為 bazel 知道tensorflow_wrapper需要什么

但是,如果您想在 bazel 之外使用它,則需要像這樣鏈接libtensorflow_framework.so.2libtensorflow_wrapper.so / libtensorflow_wrapper.a

g++ your_binary_main.cpp -ltensorflow_wrapper -ltensorflow_framework

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM