如何使用自定义protobuf构建tensorflow 1.13.1?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用自定义protobuf构建tensorflow 1.13.1?相关的知识,希望对你有一定的参考价值。

系统信息

  • 我是否编写过自定义代码:修改bazel文件
  • 操作系统平台和分发:Ubuntu 16.04
  • TensorFlow安装自:来源
  • TensorFlow版本:1.13.1从相应的标签下载(https://github.com/tensorflow/tensorflow/archive/v1.13.1.tar.gz
  • Python版本:Python 3.5.2
  • 巴塞尔版本:0.21.0
  • Protobuf版本:3.7.0(从源代码构建并放在文件系统中)
  • CUDA / cuDNN版本:10.0 / 7
  • GPU型号和内存:GeForce GTX 1060 Ti

上下文:默认情况下,tensorflow构建自己的protobuf代码。然而,protobuf也用于其他库,其导出的符号与tensorflow提供的符号相冲突。对该问题的唯一解决方案是对所有库(包括张量流)使用独特且独立(即,超出张量流)的protobuf版本。所以我基本上需要使用目标安装的protobuf版本构建tensorflow,它位于文件系统的某个位置。

问题:在构建tensorflow 1.13.1时,使用自定义版本的protobuf,安装在文件系统中的某个位置(不在默认系统路径中)。更具体地说,我的问题是:在tensorflow的bazel文件中需要进行哪些修改才能实现这一点。我是bazel的新手,我真的很困惑该怎么做......

这是我做的:

1)停用protobuf的内部构建,在.tf_configure.bazelrc我添加了一行:

build --action_env TF_SYSTEM_LIBS="protobuf_archive"

除了我在默认系统路径中安装的protobuf太旧而无法解析proto3文件之外,这可以正常工作。不管怎样,这不是一个真正的问题,因为我想使用我的自定义protobuf版本3.7.0。

2)指定在哪里找到protobuf我使用new_local_repository而不是tf_http_archive更改了workspace.bzl文件。

这里@ PATH_TO_PROTOBUF @如果我的文件系统中安装了protobuf库的路径。

    new_local_repository(
        name =  "protobuf_archive",
        path = "@PATH_TO_PROTOBUF@",
        build_file = clean_dep("//third_party/systemlibs:protobuf.BUILD"),
    )

    new_local_repository(
        name = "com_google_protobuf",
        path = "@PATH_TO_PROTOBUF@",
        system_build_file = clean_dep("//third_party/systemlibs:protobuf.BUILD"),
        system_link_files = 
            "//third_party/systemlibs:protobuf.bzl": "protobuf.bzl",
        ,
    )
    new_local_repository(
        name = "com_google_protobuf_cc",
        path = "@PATH_TO_PROTOBUF@",
        system_build_file = clean_dep("//third_party/systemlibs:protobuf.BUILD"),
        system_link_files = 
            "//third_party/systemlibs:protobuf.bzl": "protobuf.bzl",
        ,
    )

3)我通过更改规则使用的二进制文件更改了位于tensorflow-1.13.1 / third_party / systemlibs中的protobuf.BUILD文件:

cc_library(
    name = "protobuf",
    hdrs = HEADERS,
    linkopts = ["@PATH_TO_PROTOBUF@/lib/libprotobuf.so"],
    visibility = ["//visibility:public"],
)

cc_library(
    name = "protobuf_headers",
    hdrs = HEADERS,
    linkopts = ["@PATH_TO_PROTOBUF@/lib/libprotobuf.so"],
    visibility = ["//visibility:public"],
)

cc_library(
    name = "protoc_lib",
    linkopts = ["@PATH_TO_PROTOBUF@/lib/libprotoc.so"],
    visibility = ["//visibility:public"],
)

genrule(
    name = "protoc",
    outs = ["protoc.bin"],
    cmd = "ln -s @PATH_TO_PROTOBUF@/bin/protoc $@",
    executable = 1,
    visibility = ["//visibility:public"],
)

这样我认为一切都会有效,但是当我运行构建时:

ERROR: .../tensorflow-1.13.1/tensorflow/core/BUILD:2460:1: ProtoCompile tensorflow/core/lib/core/error_codes.pb.cc failed (Exit 127): protoc.bin failed: error executing command 
  (cd /home/robin/.cache/bazel/_bazel_robin/c04a70144cd329180403af87e4cbdc44/execroot/org_tensorflow && \
  exec env - \
    PATH=/bin:/usr/bin \
  bazel-out/host/genfiles/external/protobuf_archive/protoc.bin '--cpp_out=bazel-out/host/genfiles/' -I. -Iexternal/protobuf_archive -Ibazel-out/host/genfiles/external/protobuf_archive tensorflow/core/lib/core/error_codes.proto)
Execution platform: @bazel_tools//platforms:host_platform
[32 / 203] 6 actions, 5 running
    Executing genrule @protobuf_archive//:link_headers [for host]; 0s local
    ProtoCompile .../core/lib/core/error_codes.pb.cc [for host]; 0s local
    Compiling tensorflow/core/platform/default/logging.cc [for host]; 0s local
    ProtoCompile tensorflow/core/example/example.pb.cc [for host]; 0s local
    Executing genrule @local_config_cuda//cuda:cuda-include; 0s local
    [-----] Writing file external/llvm/llvm-tblgen-2.params [for host]
bazel-out/host/genfiles/external/protobuf_archive/protoc.bin: error while loading shared libraries: libprotoc.so.18: cannot open shared object file: No such file or directory

显然protoc失败只是因为加载器找不到libprotoc。

4)所以解决方案对我来说是微不足道的,只需设置LD_LIBRARY_PATH就可以自动找到libprotoc.so。遗憾的是,以下解决方案均无效:

A)直接设置LD_LIBRARY_PATH

export LD_LIBRARY_PATH=@PATH_TO_PROTOBUF@/lib
bazel build //tensorflow:tensorflow_cc.So

B)通过.tf_configure.bazelrc设置LD_LIBRARY_PATH:

build --action_env LD_LIBRARY_PATH="@PATH_TO_PROTOBUF@/lib"

输出与之前完全相同,所以我的第一句话就是不导出LD_LIBRARY_PATH(据我所知)。这可以解释为:

exec env - \
    PATH=/bin:/usr/bin \
bazel-out/host/genfiles/external/protobuf_archive/protoc.bin '--cpp_out=bazel-out/host/genfiles/' 

不包含像这样的表达式

LD_LIBRARY_PATH=@PATH_TO_PROTOBUF@/lib/ 

我google了很长时间没有找到任何解决方案来解决这个问题(我测试了很多但没有任何效果)...也许这是我使用的Bazel版本的限制?不幸的是我不能使用更新版本的Bazel,因为tensorflow 1.13.1禁止它。

所以现在我不知道该怎么做......我想解决方案是对张量流的bazel项目文件做一些修改......

答案

对于那些感兴趣的人,我找到了一个不那么优雅的解决方案,但似乎有效:

1)写一个脚本call_proto.sh

export LD_LIBRARY_PATH=@TARGET_PROTOBUF_LIB_DIR@:$LD_LIBRARY_PATH
@TARGET_PROTOC_EXECUTABLE@ $@

用足够的值替换@ TARGET_PROTOBUF_LIB_DIR @和@ TARGET_PROTOC_EXECUTABLE @(包含protoc库的库目录和protoc可执行文件的完整路径)。

2)从我之前的例子中,在tensorflow-1.13.1 / third_party / systemlibs / protobuf.BUILD中替换:

genrule(
    name = "protoc",
    outs = ["protoc.bin"],
    cmd = "ln -s @PATH_TO_PROTOBUF@/bin/protoc $@",
    executable = 1,
    visibility = ["//visibility:public"],
)

通过

genrule(
    name = "protoc",
    outs = ["protoc.bin"],
    cmd = "ln -s @PROTO_CALL_SCRIPT@ $@",
    executable = 1,
    visibility = ["//visibility:public"],
)

使用@ PROTO_CALL_SCRIPT @上一个脚本文件的路径...

这确实解决了将LD_LIBRARY_PATH传递给protoc调用的问题。

不幸的是,现在出现了另一个问题:

ERROR: /home/robin/.cache/bazel/_bazel_robin/c04a70144cd329180403af87e4cbdc44/external/protobuf_archive/BUILD.bazel:44:1: declared output 'external/protobuf_archive/google/protobuf/any.pb.h' is a dangling symbolic link
[21 / 86] 7 actions, 6 running
    Executing genrule @protobuf_archive//:link_headers [for host]; 0s local
    Executing genrule @local_config_cuda//cuda:cuda-include; 0s local
    @com_google_absl//absl/base:dynamic_annotations; 0s local
    Executing genrule @local_config_cuda//cuda:cuda-lib [for host]; 0s local
    ProtoCompile tensorflow/core/example/example.pb.cc [for host]; 0s local
    ProtoCompile tensorflow/core/example/example.pb.cc; 0s local
    [-----] //tensorflow/cc:ops/candidate_sampling_ops_gen_cc
ERROR: /home/robin/.cache/bazel/_bazel_robin/c04a70144cd329180403af87e4cbdc44/external/protobuf_archive/BUILD.bazel:44:1: declared output 'external/protobuf_archive/google/protobuf/any.proto' is a dangling symbolic link
[21 / 89] 7 actions, 6 running
    Executing genrule @protobuf_archive//:link_headers [for host]; 0s local
    Executing genrule @local_config_cuda//cuda:cuda-include; 0s local
    @com_google_absl//absl/base:dynamic_annotations; 0s local
    Executing genrule @local_config_cuda//cuda:cuda-lib [for host]; 0s local
    ProtoCompile tensorflow/core/example/example.pb.cc [for host]; 0s local
    ProtoCompile tensorflow/core/example/example.pb.cc; 0s local
    [-----] //tensorflow/cc:ops/candidate_sampling_ops_gen_cc
ERROR: /home/robin/.cache/bazel/_bazel_robin/c04a70144cd329180403af87e4cbdc44/external/protobuf_archive/BUILD.bazel:44:1: declared output 'external/protobuf_archive/google/protobuf/arena.h' is a dangling symbolic link
[21 / 89] 7 actions, 6 running
...

同样的错误消息is a dangling symbolic link出现在protobuf的所有标题。

确实在相应的protobuf_archive文件夹中,我有悬挂的符号链接,如:

any.pb.h -> /usr/include/google/protobuf/any.pb.h

据我所知,问题来自genrule link_headers

genrule(
    name = "link_headers",
    outs = HEADERS,
    cmd = """
      echo "OUTS=$(OUTS) include=$(INCLUDEDIR)"
      for i in $(OUTS); do
        f=$$i#$(@D)/
        mkdir -p $(@D)/$$f%/*
        ln -sf $(INCLUDEDIR)/$$f $(@D)/$$f
      done
    """,
)

由于INCLUDEDIR值(/usr/include)所有生成的符号链接都无效。

解决方案是修改thios规则以使其指向有效的包含文件夹:

genrule(
    name = "link_headers",
    outs = HEADERS,
    cmd = """
      for i in $(OUTS); do
        f=$$i#$(@D)/
        mkdir -p $(@D)/$$f%/*
        ln -sf @TARGET_PROTOBUF_INCLUDE@/$$f $(@D)/$$f
      done
    """,
)

与@ TARGET_PROTOBUF_INCLUDE @ protobuf的路径包括文件系统中的dir ...现在符号链接正确生成,悬空符号链接的错误消失。

我有错误报告protobuf的一些头文件是未知的......为了解决这个问题,解决方案只是为protobuf.BUILD中的HEADERS生成足够的值。我将HEADERS的值设置为:

HEADERS = [
    "google/protobuf/any.h",
    "google/protobuf/any.pb.h",
    "google/protobuf/any.proto",
    "google/protobuf/api.pb.h",
    "google/protobuf/api.proto",
    "google/protobuf/arena.h",
    "google/protobuf/arena_impl.h",
    "google/protobuf/arenastring.h",
    "google/protobuf/compiler/code_generator.h",
    "google/protobuf/compiler/command_line_interface.h",
    "google/protobuf/compiler/cpp/cpp_generator.h",
    "google/protobuf/compiler/csharp/csharp_generator.h",
    "google/protobuf/compiler/csharp/csharp_names.h",
    "google/protobuf/compiler/importer.h",
    "google/protobuf/compiler/java/java_generator.h",
    "google/protobuf/compiler/java/java_names.h",
    "google/protobuf/compiler/js/js_generator.h",
    "google/protobuf/compiler/js/well_known_types_embed.h",
    "google/protobuf/compiler/objectivec/objectivec_generator.h",
    "google/protobuf/compiler/objectivec/objectivec_helpers.h",
    "google/protobuf/compiler/parser.h",
    "google/protobuf/compiler/php/php_generator.h",
    "google/protobuf/compiler/plugin.h",
    "google/protobuf/compiler/plugin.pb.h",
    "google/protobuf/compiler/plugin.proto",
    "google/protobuf/compiler/python/python_generator.h",
    "google/protobuf/compiler/ruby/ruby_generator.h",
    "google/protobuf/descriptor.h",
    "google/protobuf/descriptor.pb.h",
    "google/protobuf/descriptor.proto",
    "google/protobuf/descriptor_database.h",
    "google/protobuf/duration.pb.h",
    "google/protobuf/duration.proto",
    "google/protobuf/dynamic_message.h",
    "google/protobuf/empty.pb.h",
    "google/protobuf/empty.proto",
    "google/protobuf/extension_set.h",
    "google/protobuf/extension_set_inl.h",
    "google/protobuf/field_mask.pb.h",
    "google/protobuf/field_mask.proto",
    "google/protobuf/generated_enum_reflection.h",
    "google/protobuf/generated_enum_util.h",
    "google/protobuf/generated_message_reflection.h",
    "google/protobuf/generated_message_table_driven.h",
    "google/protobuf/generated_message_util.h",
    "google/protobuf/has_bits.h",
    "google/protobuf/implicit_weak_message.h",
    "google/protobuf/inlined_string_field.h",
    "google/protobuf/io/coded_stream.h",
    "google/protobuf/io/gzip_stream.h",
    "google/protobuf/io/printer.h",
    "google/protobuf/io/strtod.h",
    "google/protobuf/io/tokenizer.h",
    "google/protobuf/io/zero_copy_stream.h",
    "google/protobuf/io/zero_copy_stream_impl.h",
    "google/protobuf/io/zero_copy_stream_impl_lite.h",
    "google/protobuf/map.h",
    "google/protobuf/map_entry.h",
    "google/protobuf/map_entry_lite.h",
    "google/protobuf/map_field.h",
    "google/protobuf/map_field_inl.h",
    "google/protobuf/map_field_lite.h",
    "google/protobuf/map_type_handler.h",
    "google/protobuf/message.h",
    "google/protobuf/message_lite.h",
    "google/protobuf/metadata.h",
    "google/protobuf/metadata_lite.h",
    "google/protobuf/parse_context.h",
    "google/protobuf/port.h",
    "google/protobuf/port_def.inc",
    "google/protobuf/port_undef.inc",
    "google/protobuf/reflection.h",
    "google/protobuf/reflection_ops.h",
    "google/protobuf/repeated_field.h",
    "google/protobuf/service.h",
    "google/protobuf/source_context.pb.h",
    "google/protobuf/source_context.proto",
    "google/protobuf/struct.pb.h",
    "google/protobuf/struct.proto",
    "google/protobuf/stubs/bytestream.h",
    "google/protobuf/stubs/callback.h",
    "google/protobuf/stubs/casts.h",
    "google/protobuf/stubs/common.h",
    "google/protobuf/stubs/fastmem.h",
    "google/protobuf/stubs/hash.h",
    "google/protobuf/stubs/logging.h",
    "google/protobuf/stubs/macros.h",
    "google/protobuf/stubs/mutex.h",
    "google/protobuf/stubs/once.h",
    "google/protobuf/stubs/platform_macros.h",
    "google/protobuf/stubs/port.h",
    "google/protobuf/stubs/status.h",
    "google/protobuf/stubs/stl_util.h",
    "google/protobuf/stubs/stringpiece.h",
    "google/protobuf/stubs/strutil.h",
    "google/protobuf/stubs/template_util.h",
    "google/protobuf/text_format.h",
    "google/protobuf/timestamp.pb.h",
    "google/protobuf/timestamp.proto",
    "google/protobuf/type.pb.h",
    "google/protobuf/type.proto"

以上是关于如何使用自定义protobuf构建tensorflow 1.13.1?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Protobuf.net C# 序列化自定义对象基础属性

获取自定义构建工具来创建 C# 文件

如何使用 mingw 在 Windows 中构建 protobuf-c?

从 protobuf-net 中的自定义 RuntimeTypeModel 生成 .proto 文件

使用自定义十进制原型合约(C#/C++ 互操作)时,Protobuf-net(反)序列化小数抛出

在 protobuf-net 中,有没有办法指定在序列化/反序列化给定类型时要使用的自定义方法?