Tensorflow: Java接口

创建于 2015-11-09  ·  112评论  ·  资料来源: tensorflow/tensorflow

跟踪 java swig 接口的工作的问题。 开始实施 - 将随着进度更新。 如果有人有任何意见/提示 - 欢迎加入讨论!

最有用的评论

更新:我能够成功地使用 javacpp(感谢@saudet )并让 Java 程序读取/执行 TensorFlow 模型。

https://medium.com/google-cloud/how-to-invoke-a-trained-tensorflow-model-from-java-programs-27ed5f4f502d#.tx8nyds5v

所有112条评论

好的!

将此评论从https://github.com/tensorflow/tensorflow/issues/3移至此处:


有一个具有相当好的收敛性的测试套件,但目前它主要是带有一些 C++ 测试的 Python。 还有很多用于构建图形的功能,目前仅适用于 Python,特别是自动微分功能,尽管这对于在 Java 中评估图形并不重要。 未来有计划将此功能转移到底层 C++ 中,届时 Java SWIG 绑定对于创建图形将更有用。

如果有人接受 Java SWIG 挑战,我们很乐意在上游接受审核等,届时它将成为我们持续测试的一部分。 接受捐款的细节目前在不断变化,但会稳定下来。

大家好
我们也有兴趣使 TensorFlow 适应 Java。 @ravwojdyla你有没有机会开始研究 Java 的 Swig 接口? 如果你有,我们可以加入我们的努力并就此展开合作

你好,
我正在研究主要 C++ API 的 SWIG 包装。 你可以在我的叉子上看到我到目前为止的进展,但上面的东西还没有完成; 我目前遇到了#include "tensorflow/core/lib/core/error_codes.pb.h"无法解决的问题,我无法在项目文件中的任何位置找到所需的文件。 任何类型的输入将不胜感激。

有 javacpp 预设可用于 Caffe 和 OpenCV 等库。 另请参阅https://github.com/bytedeco/javacpp-presets/issues/111。 Java-cpp 也通过 RoboVM 启用 IOS

/cc @saudet

@pslam - 我能够在这方面做一点工作 - 绝对可以使用一些帮助!

大家好,我相信我有非常实用的 JavaCPP 绑定: https :

做得很好@saudet! 我几乎完成了 SWIG 包装,但您的实现似乎也能正常工作。 我没有看到我的 SWIG 包装可以做而你不能做的任何事情。 JavaCPP 看起来很酷,我将不得不考虑在未来的项目中使用它。

@kylevedder ,您是否解决了与error_codes.pb.h相关的问题?
[编辑]
所有 .pb.h 文件都是从 .proto 编译的

@tngan是的,这也是我发现的。 此外,此项目中的.proto文件需要使用 ProtoBuff3。 我使用的是 Ubuntu 14.04 并且 ProtoBuff3 在我的包管理器中不可用,所以我从源代码编译它,我从3.0.0 beta 版本获得

我试图解决的当前障碍是如何让 ProtoBuff 递归整个文件树并将.proto文件编译成.h.cc文件; 由于对其他尚未编译的.proto文件的依赖性不满意,因此逐个执行每个文件夹会导致失败。

@kylevedder您的 SWIG 包装器是在单独的存储库中还是在 tensorflow 存储库中工作? protoc工作方式与其他编译器类似。 如果您在 tensorflow 存储库中工作或正在使用 Bazel,那么您需要设置 protobuf 构建目标以及它们之间的依赖关系。

如果您在单独的存储库中工作并使用不同的构建系统,那么您需要为该构建系统使用 protobuf 插件。

如果您愿意,我很乐意帮助您设置构建。

@davidzchen谢谢你的提议,非常感谢任何和所有的帮助。

到目前为止我所拥有的:

我已经设置了 Bazel 并将其编译成.whl文件,然后我将其交给pip并确认我可以运行第一个 TensorFlow 程序

我在我的分叉存储库中生成了 SWIG 包装器文件。 它们位于core/javaWrapper下的文件夹中。 [[链接](https://github.com/kylevedder/tensorflow/tree/master/tensorflow/core/javaWrapper)]

我正在尝试做的事情:

最终,我的目标是生成一个.so文件,该文件可以在 Java 中作为本机库调用。 目前,我正在尝试使用 g++ 将整个系统编译成.so文件; 但是, .proto文件需要在编译之前首先扩展为.h.cc ,这就是我要对protoc做的事情

您可以在此处看到我对包装脚本的尝试,以可能更好地了解我在做什么,尽管到目前为止我使用protoc所有尝试都是逐个目录的,因此,不是在脚本中。

最后,对改进领域的任何反馈将不胜感激。 谢谢!

@kylevedder我已经有一个.so构建作为 JavaCPP 预设的一部分: https :

diff -ruN tensorflow/tensorflow/cc/BUILD tensorflow-patch/tensorflow/cc/BUILD
--- tensorflow/tensorflow/cc/BUILD  2015-11-22 00:00:02.441829192 +0900
+++ tensorflow-patch/tensorflow/cc/BUILD    2015-11-14 11:15:12.689330351 +0900
@@ -75,6 +75,17 @@
     ],
 )

+cc_binary(
+    name = "libtensorflow.so",
+    copts = tf_copts(),
+    linkshared = 1,
+    deps = [
+        ":cc_ops",
+        "//tensorflow/core:kernels",
+        "//tensorflow/core:tensorflow",
+    ],
+)
+
 filegroup(
     name = "all_files",
     srcs = glob(

并像这样运行 Bazel,例如:

bazel build -c opt //tensorflow/cc:libtensorflow.so

AFAIK,这应该会吞噬几乎所有对 C++ API 感兴趣的东西。

@saudet是否有理由使用cc_binary规则来构建共享库而不是cc_library ? 您可以使用名为tensorflowcc_library规则,构建目标将构建一个名为libtensorflow.so的共享库。

@kylevedder如果您的目标是生成一个.so文件,那么类似于@saudet建议的内容将起作用。

如果您需要在 Java 代码中使用 TensorFlow protos,那么您需要将java_* Bazel 构建目标中的依赖项添加到proto_library目标中,以从.proto生成 Java 类

在我们开源原生proto_library规则之前,我们还有一些工作要做(参见 bazelbuild/bazel#52),但与此同时,TensorFlow 使用了cc_proto_librarypy_proto_library protobuf 提供的,对于 Java,您应该能够使用Bazel 中包含proto_library的时间表是什么,以及是否值得将 Protobuf 提供的规则与genproto统一起来。

其他一些反馈:

  • 我认为最好保持目录名称一致并使用java_wrapper而不是javaWrapper
  • 也许 Java 包装器的更好位置是//tensorflow/java/wrapper而不是//tensorflow/core/java_wrapper
  • 在内部,我们有一些使用.swig文件并生成源的构建规则。 这是更理想的,因为我们将避免签入生成的文件。 我可以看看我们为 Bazel 添加一些 SWIG 构建规则以简化这样的事情对我们来说有多困难。

@davidzchen没有特别的理由。 我是 Bazel 的新手,只是使用linkshared=1就像我在邮件列表中看到的那样工作。 所以谢谢你的提示! 我会更新那个。

@saudet谢谢! 我只是检查以确保这不是 Bazel 的问题。 :) 如果您遇到任何问题,请随时告诉我或打开一个错误。

@saudet感谢您提供有关使用 Bazel 的信息。 我也是新手,并没有意识到它能够以这种方式生成.so

@davidzchen感谢有关使用cc_library附录,当我实现Bazil 包装器构建时,我相应地修改了@saudet 中的示例。 另外,感谢您提供有关目录结构的意见; 我已经更新了我的文件夹结构以符合您的建议。

此外,我在之前关于生成.so文件的评论中不是很清楚; 虽然我的目标是从原始源生成.so文件,但我还想将SWIG 生成的.cxx文件包含在.so中,以便于 JNI调用。 目前,我遇到了一个问题,我无法编译 SWIG 生成的.cxx文件; 它试图引用JNI.h ,一个位于$JAVA_HOME/include/的标头,但我似乎无法让 Bazel 理解外部包含路径。

@davidzchen嗯,不, cc_library不起作用。 我没有看到任何其他方法可以让 Bazel 将-shared选项传递给编译器: http :

@saudet我认为您不需要自己传递-sharedcc_library应该默认构建一个.so 。 那对你有用吗?

@kylevedder您将无法以这种方式添加 JNI 标头,因为它们位于工作区之外。 但是,Bazel 将本地 JDK 作为本地存储库包含在内,并提供了许多可用于依赖本地 JDK 的内置目标(请参阅jdk.WORKSPACE和相应的jdk.BUILD )。 默认情况下,这些都包含在每个 Bazel 工作区中。

Bazel 本身使用 JNI 并以这种方式与本地 JDK 接口(参见src/main/native/BUILD )。 在这个 BUILD 文件中,有两个genrule用于复制 JNI 标头和一个cc_library目标,用于它正在构建的库使用依赖于标头的 JNI,以及一个includes = ["."]以便 C++ 代码可以包含带有#include <jni.h>的 JNI 标头。 这目前没有记录,因为我们正在对外部存储库机制进行一些改进, @local-jdk名称可能会更改,但我们可以将它用于 TensorFlow 和任何其他同时使用 JNI 的 Bazel 项目.

这是您的 BUILD 文件的补丁,它添加了genrule目标以复制您需要的 JNI 标头,并对cc_library目标进行一些更改以设置正确的依赖项,即:

  1. 添加jni.hjni_md.h ,由genrule复制到当前包中srcs
  2. 添加对//tensorflow/core的依赖,以便您可以在tensorflow/core/public下包含标题。 请注意,从 Bazel 的角度来看,单独目录中的头文件或任何源文件位于单独的包中,您需要在包含这些文件的构建目标上添加依赖项。
diff --git a/tensorflow/core/java/wrapper/BUILD b/tensorflow/core/java/wrapper/BUILD
index 72b4076..04a3394 100644
--- a/tensorflow/core/java/wrapper/BUILD
+++ b/tensorflow/core/java/wrapper/BUILD
@@ -7,10 +7,30 @@ exports_files(["LICENSE"])
 load("/tensorflow/tensorflow", "tf_copts")
 load("/tensorflow/tensorflow", "tf_gen_op_wrappers_cc")

+genrule(
+    name = "copy_link_jni_md_header",
+    srcs = ["//external:jni_md_header-linux"],
+    outs = ["jni_md.h"],
+    cmd = "cp -f $< $@",
+)
+
+genrule(
+    name = "copy_link_jni_header",
+    srcs = ["//external:jni_header"],
+    outs = ["jni.h"],
+    cmd = "cp -f $< $@",
+)
+
 cc_library(
     name = "java_wrapper",
-    srcs = glob(["*.cc","*.cxx","*.h"]),
-    copts = ["-I$$JAVA_HOME/include/", "-I$$JAVA_HOME/include/linux/"],
+    srcs = glob(["*.cc", "*.cxx", "*.h"]) + [
+        ":jni.h",
+        ":jni_md.h",
+    ],
+    includes = ["."],
+    deps = [
+        "//tensorflow/core",
+    ],
     visibility = ["//visibility:public"],
 )

请注意,通常,Bazel 中的编译操作是从源代码树的根目录运行的,您需要按如下方式更改 SWIG 文件中的包含,然后重新生成 C++ 文件,以便它们具有正确的包含:好:

diff --git a/tensorflow/core/java/wrapper/tensor_c_api.i b/tensorflow/core/java/wrapper/tensor_c_api.i
index d08b571..9ab1fa1 100644
--- a/tensorflow/core/java/wrapper/tensor_c_api.i
+++ b/tensorflow/core/java/wrapper/tensor_c_api.i
@@ -1,8 +1,8 @@
 %module tensor_c_api_module
 %{
-#include "../../public/tensor_c_api.h"
+#include "tensorflow/core/public/tensor_c_api.h"
 %}
-%include "../../public/tensor_c_api.h"
+%include "tensorflow/core/public/tensor_c_api.h"
 %include "stddef.h"

一旦成功,您就可以为 Linux 设置 JNI 构建,因为copy_link_jni_md_header genrule仅复制 Linux 特定的标头。 要让它复制正确的特定于平台的 JNI 标头,我们需要执行以下操作:

  1. 为其他平台设置cpu config_setting s。 目前,tensorflow 在tensorflow/python/BUILDconfig_setting--cpu=darwin tensorflow/python/BUILD 。 我们可能应该移动一个更合适的包,例如//tensorflow/core 。 基本上,我们想要与 Bazel 相同的一组config_setting s(参见src/BUILD )。
  2. 根据使用select()设置的配置设置,让copy_link_jni_md_header复制正确的 JNI 标头,类似于Bazel 中的设置。 我们的genrule看起来像下面这样:
genrule(
    name = "copy_link_jni_md_header",
    srcs = select({
        "//tensorflow/core:darwin": ["//external:jni_md_header-darwin"],
        "//tensorflow/core:darwin_x86_64": ["//external:jni_md_header-darwin"],
        "//tensorflow/core:freebsd": ["//external:jni_md_header-freebsd"],
        "//conditions:default": ["//external:jni_md_header-linux"],
    }),
    outs = ["jni_md.h"],
    cmd = "cp -f $< $@",
)

如果您遇到任何问题,我很乐意为您提供帮助。 让我知道这是否适合您。

@davidzchen cc_library 生成一堆 .a 文件,但没有 .so 文件。 我正在使用 0.1.0,正如之前为 TensorFlow 推荐的那样......也许它已在 0.1.1 中修复? 我得再试一次。

@davidzchen非常感谢您的帮助。 我已按照您的说明进行操作,并按照您的建议更新了 Java 包装器BUILD文件以及SWIG .i文件。 此外,我将包装脚本从core/java/wrapper到根目录并相应地更新了链接。

现在,我已经跳过了jni_md.h文件的genrule泛化,而是专注于尝试构建libtensorflow.so 。 不幸的是,在我看来似乎没有生成libtensorflow.so ; 我最终在我的整个文件系统中搜索任何名为“libtensorflow”的变体的东西,但没有出现任何相关内容。 它可能命名不同,或者这可能是用户错误的简单情况。 此外,它可能与@saudet.so代的cc_library规则中遇到的问题有关。

再次感谢您的帮助,我真的很感激。

对不起,事实证明我错了。 为了构建包含传递依赖项的.so@saudet使用cc_binarylinkshared = 1name = "libtensorflow.so"所做的操作是正确的。 从cc_binary.linkshared文档

创建共享库。 要启用此属性,请在您的规则中包含 linkshared=1。 默认情况下,此选项处于关闭状态。 如果启用它,则必须将二进制文件命名为 libfoo.so(或目标平台上任何库的命名约定)以获得 foo 的一些合理值。

之间的主要区别.so的由内置cc_library靶和.so内置cc_binary使用上述的方法,是在cc_library工件仅包含srcs的代码。 这就是为什么在没有srcs而只有deps构建cc_library目标,例如//tensorflow/core ,不会产生任何工件。 另一方面, cc_binary目标将链接所有传递依赖项。

对于造成的混乱,我深表歉意。 也许我们应该改进我们的文档并添加一个关于构建.so的示例。

我想您应该按照这些步骤来构建 Tensorflow 及其所有依赖项。 我们正在将 TensorFlow 移植到 node.js,我已经实现了一个 shell 脚本来编译和获取整个 repo 中的基本源:
https://github.com/node-tensorflow/node-tensorflow/blob/1.0.0/tools/install.sh#L233 -L282

@davidzchen感谢您提供有关创建.so 。 我已经相应地更新了我的设置,并创建了一个带有 _extremely_ 基本测试器的tensorflow/core/java/wrapper/example来证明 JNI 函数调用.so工作。 请注意, createWrapper.sh必须在运行compileAndRun.sh之前运行。

我将尝试改进 SWIG 包装器并制作一个更好的示例,我现在拥有的只是工作绑定的最低限度证明。

最后,我要感谢@davidzchen@saudet的所有帮助; 如果没有他们,我将无法做到这一点。

好的! 感谢您的工作,@kylevedder!

如果您有兴趣,我可以尝试通过 1) 创建 Skylark SWIG 规则和 2) 使用Bazel 的 Java 规则构建 Java 代码,将您的createWrapper.shcompileAndRun.sh脚本集成到 Bazel 构建中。

@davidzchen那太好了! 我将致力于改进 SWIG 包装器和基本示例。

我已经完成了 JavaCPP 的预设并移植了example_trainer.cc示例:
https://github.com/bytedeco/javacpp-presets/tree/master/tensorflow
期待将其与使用 SWIG 的等效包装器进行比较!

看起来 API 链接已损坏: http :

@verdiyanto抱歉,我还没有 CI,但是上传 API 文档很容易,所以我至少已经做到了。 享受!

@saudet在 JavaCPP 预设方面

我的工作更新:我在 SWIG 包装器上做了一些更多的工作,你可以在这里看到我所做的工作。 但是,我正处于一个十字路口,我不确定最好的前进方式。

我对 SWIG 比较陌生,因为这是我使用它的第一个主要项目,所以我阅读了SWIG 基础知识以及SWIG 和 Java上的 SWIG 文档,其中介绍了 SWIG 的工作原理以及如何使用 SWIG Java 包装器包装 C/C++。

该文档解释了 SWIG 如何将 C/C++ 中的指针转换为不透明的 Java 对象,这就是您获得 SWIG 生成的SWIGTYPE_p_void等类的原因。 问题是没有一种简单的方法可以将 POJO 转换为这些 SWIG 类。

因此,例如,在tensor_c_api.h ,C 方法TF_CreateTensor()使用指向输入数据的void*size参数来指定数据的大小以字节为单位的输入数据。 对于 C/C++ 来说,这是一个完全合理的设计模式,但在 Java 中完全没有意义。 SWIG 生成的 Java 方法TF_CreateTensor()SWIGTYPE_p_void对象以及size对象作为其数据,但是无法转换诸如String类的 POJO SWIGTYPE_p_void无需手写大量代码。

这就是我目前所处的十字路口:我要么编写大量 C/C++ 转换方法,这些方法采用TF_DataType定义的任何类型并转​​换为void* ,或者编写一堆SWIG typemaps 来做同样的事情。 SWIG 文档似乎并不支持这两种解决方案,因为它们似乎可以互换。

那么,问题是,C/C++ 转换函数还是 SWIG 类型映射?

@kylevedder我看到你开始理解我为什么首先创建 JavaCPP。 :)

我一直在使用@saudet的 JavaCPP 预设,非常有用,谢谢! 我正在使用它来构建一个 Clojure 接口到 tensorflow。

一些评论:

a) 有机会简化/更高层

很多 JavaCPP api 复制了 protobuf 功能,可以直接在 JVM 上实现,无需桥接。 我花了一点时间才意识到这一点,但一个是简单地使用 JavaCPP 绑定构建一个 protobuf 对象,使用互操作生成这种与平台无关的表示,然后将其填充到会话中。

我最终只是使用基于 jvm 的 protobufs 来直接构建图形,绕过 JavaCPP 构造函数。 这有几个优点——一个更简单的编程接口,还有很好的 .toString 格式,显示了人类可读的 protobuf。

特别是对于 Clojure,用数据结构来描述张量流图然后将它们直接转换为 protobuf 比在我的数据结构中为每个节点查找和调用构造函数要容易得多。

b) 构建和包改进

我不是构建本机代码的专家,也不是这些项目中使用的构建工具的专家。 拥有 Maven 化的工件会很棒; 特别是如果它们还包含生成的 java protobuf 类。 我花了很长时间才弄清楚如何做到这一点。

c) 以少量图形测试用例为目标会很有用。

现在我的方法有点麻烦:使用 JavaCPP 构造函数生成一个图形,将它混入我的 JVM protobufs 并查看人类可读的形式,并弄清楚如何构建我自己的构造函数来制作相同的形式。

拥有一小部分非常简单的图表来练习 TensorFlow 的核心功能会很有用,这样像我这样的人就有了一组合理的测试用例来针对不同语言的互操作。

无论如何,感谢大家的努力,并保持良好的工作!

@kovasb感谢您的反馈! 显然,要使接口对 Java、Scala、Clojure 等更自然,还有很多工作要做。

如果您有帮助类将 C++ API 与 Java protobuf API 集成,请随意将所有这些放在以下包中,包括生成的 Java protobuf 类本身,并发送 PR:
https://github.com/bytedeco/javacpp-presets/tree/master/tensorflow/src/main/java/org/bytedeco/javacpp/helper
这就是它的意义所在,它会自动打包在 Maven 工件中,而 Bazel 似乎不支持。 无论如何,感谢您对此进行调查!

@kovasb clojure 界面听起来很有趣。 有任何代码要分享吗?

谢谢!

因此,该线程中的人们也知道,在https://github.com/tensorflow/tensorflow/issues/3中已提出:除非您使用 python api 中的 TF,否则当前无法自动区分。 这似乎是一个等待该功能被移植到 C++ 的障碍。

我不太了解数据流,但也许可以将 python 帮助程序与 C++ 库一起启动?

我正在考虑的另一个解决方案是仅使用 Jpy 或其他桥接器之一(有人有推荐吗?)JyNi 看起来也很有趣,但离黄金时段还很远(尽管看到更多的动力/社区支持它会很棒)

如果 JyNi 得到解决,它 + jython 将为 JVM 提供一个非常棒的关于 Python 生态系统互操作的故事。 一个人可以做梦。

+1 用于 Java 接口!

如果我们可以使用 javaCPP,还需要 SWIG 吗? 我们应该合作实现 SWIG 接口吗?

@maxiwu我喜欢认为 JavaCPP 比 SWIG 做得更好,但我完全赞成将它们进行比较以实际证明它:)

@kovasb我对帮助/贡献 Clojure 界面非常感兴趣。

@sorenmacbeth 用我在 gmail 的名字点电子邮件,很高兴带你了解我所拥有的......

似乎我们这里有一个相当完整的 Javacpp 预设。 这是“团队”可以接受的解决方案吗?

@saudet我正在尝试构建 JavaCPP 包装器的副本,但似乎由于 tensorflow 源的快速变化,它们与 0.6.0 版本或今天的主分支都不兼容。 是否可以使用指向他们测试的确切 tensorflow 提交/版本的指针来更新它们?

@nikitakit我刚刚在这里更新了 master 分支: https :

不过与 Caffe 不同的是,TensorFlow 实际上似乎每个月都会发布一个版本,所以我想我会在这些点开始稳定绑定,从下一个版本(0.7.0?)

@martinwicke你怎么看?

当有一个稳定的 Java 绑定时,我很高兴在 Scala API 上工作。

/ cc @databricks

@kovasb我想我第一次错过了。 你是说我们通过 python 使用 TensorFlow 获得的所有漂亮的自动微分魔法都是在 python 中实现的,而不是在 c++ 库中实现的? 所以在实践中,Java API 要么需要重新实现所有这些,要么只是另一个数字库? 我对 TensorFlow 的内部结构或 python 胶水不够熟悉,无法准确了解在何处完成了哪些繁重的工作。

@drdozer这是我的理解,基于@girving 的评论,然后我自己查看了一下来源。 用 Java 重新实现东西似乎是不可能的。 我建议查看 #3 中的评论

如果有人真的很感兴趣,我会建议尝试使用 Java api 做一些训练示例(到目前为止,我刚刚看到/完成了前进的道路)。

我想知道使用 Jython 运行 Python 代码能走多远……

我相信 Python API 层有很多 C++ 层 API 没有公开的逻辑。
我试图遵循 JavaCpp 路径,但最终会有大量重复代码,并且当 Python 实现中的某些内容发生变化时将难以保持一致性。

可能更简单的方法是使用 Jython,正如@saudet之前提到的那样......

它在https://github.com/tensorflow/tensorflow/issues/476中分配给 @josh11b。 如果他正在研究这个,那么使用 Jython 是没有意义的。

如果我们使用 jython,c++ 代码还能工作吗? 我希望将它用于 Java 中的服务器,但我在直接尝试 Java 路由或仅通过套接字将数据发送到 Python 进程之间陷入困境

我想提一下,虽然 Java API 没有包含很多诸如自动微分之类的功能,但我没有发现这对我自己的工作造成了障碍。 我在 python 中生成模型,将其序列化为 .proto 文件,然后通过 Java 包装器打开它进行训练取得了巨大成功。 测试时也可以这样做,因为我相信 Saver 功能可通过 C++ 和 Java API 获得。

+1

@saudet
感谢您为 tensorflow 创建 javacpp 和预设。 我能够成功地用 Java 重新创建 Python 图,但是我在尝试从保存的模型文件中恢复时遇到了困难。 此行不起作用:

Tensor fn = new Tensor(tensorflow.DT_STRING, new TensorShape(1));
CharBuffer 缓冲区 = fn.createBuffer();
buffer.put("modelfile.tf");
session.Run(...);

但 CharBuffer 原来是 NULL。 如果我将 DT_STRING 更改为 DT_FLOAT,我会得到一个 FloatBuffer,但 DT_STRING 似乎不起作用。

@nikitakit你说过你可以使用它。 你能分享你的代码吗?

@拉克什曼诺克

编辑:抱歉,误读了您在这里所说的内容。 我无法为使用 Java 的外部保护程序提供任何帮助

作为参考,我导入张量流图的代码部分在这里: https ://gist.github.com/nikitakit/d3ec270aee9d930267cec3efa844d5aa

它在 Scala 中,但移植到 Java/其他 JVM 语言应该很简单。

不幸的是,我在图中实际运行节点的代码与我正在使用的 Scala 框架密切相关,因此您将不得不依赖 tensorflow API 文档来完成这部分工作。

有没有人在 jvm 中嵌入 python tensorflow 环境? 用jython + JyNI 说? 或者这一切都过于实验性,无法可靠地工作?

我目前正在扩展 C API 以添加对图形定义的支持。 不确定什么时候会完成,但这是我们 1.0 之前的目标之一。

我正在使用 java 中的张量流。 我正在通过使用 jython 并修改张量流 cpython 库以适应另一个 python 解释器来解决这个问题。 cpython 应该继续正常工作,我的代码正在检测解释器是否是 Jython 并修改导入/模块以允许它工作。 在它下面使用 libtensorflow_cc.so 的 javacpp 绑定。 这是谷歌团队愿意在官方回购中拥有的东西吗? @vrv

这似乎是一个很好的概念证明,但我认为官方绑定可能比通过 Python 更本地地绑定:(

不,我们不调用 c-python 包装器,而是调用 javaccp 包装器。 因此,它与 cpython 张量流相同,但使用 Jython 从 JVM 进行评估。 用另一种语言重新实现整个 python 逻辑似乎太多了,你最终会得到另一个 API。 javacpp 绑定允许您毫无问题地运行推理,但目前必须从 cpython 脚本构建/训练模型。

有没有人考虑过让 tensorflow 与 Kotlin 一起工作? 这似乎更自然,而且在一天结束时它仍然是 100% 的 Java。 我发现 Kotlin 语言是 Python 和纯 Java 之间的一个很好的中间地带。

更新:我能够成功地使用 javacpp(感谢@saudet )并让 Java 程序读取/执行 TensorFlow 模型。

https://medium.com/google-cloud/how-to-invoke-a-trained-tensorflow-model-from-java-programs-27ed5f4f502d#.tx8nyds5v

感谢@lakshmanok@saudetjavacpp项目似乎实现了大多数 TensorFlow API。 我们正在尝试在 Java 中运行tensorflow/serving

API 很简单,由protobuf 。 现在我们已经实现了服务器并希望在 Java 中实现客户端。 它只需要在 Java 中构造TensorProto并调用gRPC调用。 TensorFlow 提供了帮助函数来转换 Python 和 C++ 的多维数组,但不是 Java。

你能告诉如何使用javacpp或为此自己实现吗?

您正在寻找的可能已经在https://github.com/bytedeco/javacpp-presets/blob/master/tensorflow/src/main/java/org/bytedeco/javacpp/helper/tensorflow.java但让我知道如果那里缺少某些东西。 谢谢!

这个还在处理中吗? 这个移植项目有官方的 github repo 吗? 我看到几个随机的回购,但不知道。

是的,但可能在十月/十一月的某个时候。 我们使用 C API 而不是 SWIGing 到 C++ API。 同时,您可以使用 saudet 提到的绑定。

您是如何得出使用 C API 的结论的? 我们正在研究一个
使用 swig 的 ruby​​ 界面:
http://github.com/somaticio/tensorflow.rb

2016 年 9 月 13 日星期二下午 6:22,Jonathan Hseu通知@github.com
写道:

是的,但可能在十月/十一月的某个时候。 我们正在使用 C API
而不是 SWIGing 到 C++ API。 在此期间,您可以使用
saudet 提到的绑定。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/tensorflow/tensorflow/issues/5#issuecomment -246844192,
或静音线程
https://github.com/notifications/unsubscribe-auth/AAA5v3g86Z6D1rz-aTGdMyMWnQZhrZUYks5qpyIJgaJpZM4Getd8
.

展望未来,我们希望所有语言绑定都使用 C API。 文档即将发布。

您可以在此处查看示例用法:
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/go

不过,没有紧迫性,目前在 SWIG 之上构建还不错。

@jhseu 这是否意味着 C API 将被扩展以涵盖 Python 绑定当前可以访问的所有内容?

哇,大变化。 希望早点决定。 无论如何要查看文档
早点?

2016 年 9 月 14 日星期三下午 5:56,Samuel Audet通知@ github.com
写道:

@jhseu https://github.com/jhseu 这是否意味着 C API 将是
扩展以涵盖 Python 绑定当前可以访问的所有内容?


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/tensorflow/tensorflow/issues/5#issuecomment -247167887,
或静音线程
https://github.com/notifications/unsubscribe-auth/AAA5vwfBJoZC2s33_7E9Xy6-NYNUjHjnks5qqG2FgaJpZM4Getd8
.

@saudet大多数功能,除了在短期内它会缺少一些东西(如渐变、优化器)。
@jtoy您并不急于迁移。 SWIG 将继续工作一段时间。

文档只描述了如何做和命名约定。 不过,您可以在没有它们的情况下开始迁移到 C API:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h

谢谢@saudet 。 我在stackoverflow 中找到了关于使用纯 protobuf API 生成TensorProto 。 这是 TensorFlow 服务 gRPC Java 客户端的示例代码

@tobegit3hub很好,如果您可以使用 C++ API 来实现此功能,请将其添加到 JavaCPP Presets 的帮助程序包中并发送拉取请求! 这家伙会对类似的东西感兴趣: https :

@girving javacpp是否已经解决了问题?
我想为 tensorflow java api 做出贡献,我更喜欢像 python 一样实现它。

大家好,有人已经开始使用 C API 处理 Java/Scala 语言绑定了吗?
(而不是建立在 SWIG 之上)

我有一个工作的 Java/Scala 接口到 tensorflow 只使用 C API 通过JNR 。 不幸的是,我还没有权限将其开源。 如果我发布它,我会在这里发布。 它仍在进行中,但它非常实用。

@jdolson您公开的 API 是否接受 TensorFlow 的协议缓冲区对象? 我在使用 @saudet 的 javacpp 预设时遇到的最大问题之一是,当您在 Java 客户端代码中操作张量对象时,您正在处理一个 org.tensorflow.framework.TensorProto,它由协议缓冲区编译器生成配置为输出java。 但是在 TensorFlow API 包装器中,您正在处理一个 org.bytedeco.javacpp.tensorflow.TensorProto.TensorProto,它是由 javacpp 生成的,当指向协议缓冲区编译器在配置为生成 C 时生成的 c 代码时。由于类型不是'同样,在调用封装的 TensorFlow API 时,您不能直接使用 Java 代码的张量。

@Intropy是的,我使用protoc所有 tensorflow *.proto源编译为 Java 源代码,并在 API 中使用这些类。

@jhseu C API 接口是否仍

@eaplatanios :C API 大部分是稳定的(并且将在 1.0 正式稳定)并且可用但不完整(仍然缺少自动对图形进行梯度计算的能力)。 描述如何使用 C API 构建语言绑定的文档位于https://www.tensorflow.org/how_tos/language_bindings/index.html

Go API是使用 C API 作为遵循上述文档的第一个示例实现的。

我们也希望在此基础上构建 Java 绑定(使用 JNI)并开始对此进行一些探索。 任何基于使用@saudet使 JavaCPP 工作的出色工作的评论/学习知识都会很高兴知道。

我确实有一些基于使用 JavaCPP 绑定的建议。

首先,由于协议缓冲区直接编译为 java,因此应使用 java 版本。 最好我认为参与 API 的协议缓冲区应该作为 maven 模块单独提供,并且应该带有 proto 定义,以便 Java 堆栈上的人们可以轻松地将定义作为二进制和简单的获取 proto 定义以包含在其他 proto 定义中的方法。

其次,找到 TensorFlow 需要的最低版本的 libc 并针对该版本进行构建会很有帮助。

第三,使用精心设计的 API 比使用自动生成的 API 要容易得多。 我知道这很明显,听起来像是对 JavaCPP 的一次尝试。 我不是这个意思。 我真的很高兴自动生成的界面存在。 它_是_可用的。 但是它需要奇怪的迂回,它有很多缺点,而且很难阅读代码来弄清楚如何做你想做的事情。 我希望这个建议比“你应该做得更好”更有帮助,但我想重点是看 C++ API 和 python API 有多么不同。 两者都很简单,因为它们以一种自动转换的代码不太可能匹配的方式适合他们的环境。

支持 Swig 的 C 后端并通过 Swig 生成 TF C API 可能会更好: https :

我们有一个现有的 C API,用于添加对具有 C FFI 的任何语言的支持:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h

(这就是用于为 TensorFlow 构建 Go、Java、Rust 等绑定的内容)

可以使用JNA访问 C API 吗?

@jhseu我的意思是,它可能是在手动实现 C API 之前从 C++ API 生成的。

@Quantum64是使用 JNA 的张量流的 Scala 绑定。

由于这个问题仍然存在,如何
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/java
正在实施,提交的 PR 是什么?

@hsaputra :你能详细说明你在找什么吗? 有多个提交对tensorflow/java的代码有贡献,其中大部分都在本期中被引用(例如 2b1cd28、d73a266 以及介于两者之间的许多其他提交)

@asimshankar ,感谢您的回复。

我只是想知道tensorflow/java实现 Java API 的路径是什么,因为这张票没有关闭。
有关于使用 JavaCPP、SWIG 和通过 Jython 调用的讨论。

似乎tensorflow/java是用直接 JNI 实现的,以调用 C API?

正确的。

嘿,

我昨天刚让这些 Swig 绑定工作。 我有一个 API 更改请求。 目前为了生成 Tensors 需要反射,并且数组的格式有点笨拙,因为它们需要使用 n 维原生 Java 数组。 我们可以保留这个接口,同时添加一些方法来创建需要一维数组的张量并使用另一个 long 数组指定形状吗? 我想它可能看起来像这样:

double[] matrix = {1.414, 2.718, 3.1415, 3.4, 56.7, 89.0};
long[] shape = {2, 3};

// add a method for each primitive type
org.tensorflow.Tensor tensor = org.tensorflow.Tensor.createDouble(matrix, shape);

这也将导致创建 int8、int16、uint8、uint16、uint32 张量的可能性,这将有助于兼容性。

我应该提出这个问题吗? 或者这里可以吗?

此外,非常乐意尝试构建这些方法。

@hollinwilkins :我希望 PR #6577 可以解决这个问题,只需对您提议的工厂方法稍作调整:

Tensor tensor = Tensor.create(shape, DoubleBuffer.wrap(matrix));

@asimshankar这太棒了! 感谢您的快速回复。 看起来它也非常接近合并:+1:

我正在尝试使用新的 Java API,但我遇到了一些比我认为的更难使用的事情:

  1. Java API 应该接受一个 GraphDef 对象。 目前它只接受一个字节数组,表示 GraphDef 协议缓冲区的序列化二进制文件。 在库边界需要序列化/反序列化步骤很奇怪。
  2. Session.Runner.feed 应该能够接受 org.tensorflow.framework.TensorProto 或者应该有一种从 org.tensorflow.framework.TensorProto 创建 org.tensorflow.Tensor 的好方法。
  3. Session.Runner.run 返回一个 Tensor 对象列表。 与上面类似,应该有一种简单的方法可以直接或通过给 org.tensorflow.Tensor 一种转换为 TensorProto 的好方法来获得 TensorProto 输出。
  4. Session.Runner.run 吞下状态。 应该有一种方法可以获取有关失败的信息,也许是通过抛出异常。

此外,我可能错过了处理这个问题的方法,但在我看来,我无法在 run 的输出中获得所有支持的张量类型。 例如,如果我的输出张量是 dtype INT16,则无法从中提取值。 没有 Tensor.shortValue 之类的,并且 Tensor.intValue 似乎需要完全匹配。 我基于阅读 tensor_jni.cc 中的 DEFINE_GET_SCALAR_METHOD。

@Intropy :感谢您的评论,它们绝对有道理。 现在我可以和你分享一些快速的想法:

RE:protobufs:在这一点上,出于多种原因(包括在资源受限的系统上使用nanproto 之类的

所以,回到你的观点:

  1. 看上面。 不过,我敢打赌,在很多情况下byte[]更有意义(例如从文件或网络频道读取图形)

  2. 取点

  3. 看上面。

  4. Session.runner.run应该被吞咽的状态。 如果出现错误,则会抛出异常( session_jni.cc:166 )。 如果这没有发生,请提交一个错误。

您是对的,并非所有类型都受支持,但应该很容易添加。 如果您迫切需要缺少的类型,请随时提出问题和/或发送 PR。 欢迎投稿:)

@asimshankar感谢您的想法。

关于第一点,这并不是什么大问题。 正如您所说,有时 byte[] 最有意义。 在我自己的用例中,我有一个 InputStream,转换为 byte[] 很简单。 协议缓冲区 API 使转换变得简单。 我只是认为 byte[] 是 API 上的一个问题,因为无论如何你都必须反序列化(在 TF_GraphImportGraphDef 中),这样你就失去了一些类型安全性。 还有 proto3 的 json 序列化需要考虑。

关于吞咽状态,你是对的。 我错过了未经检查的异常。

处理 2 和 3 的最明显的方法是给 org.tensorflow.Tensor 一个从 TensorProto 和一些 toTensorProto() 转换而来的工厂。 如果资源有限的用例是协议缓冲区的问题,那么在这种情况下的人们就不能使用这些功能。 问题在于,确实使用这些函数的人将支付转换成本,而通过让 Tensor 将其数据直接存储在 protobuff 中可能可以避免这种成本。 我以前从未与 jni 合作过,所以我在跟踪数据的存储方式时遇到了麻烦,但看起来它本质上是将 nativeHandle 视为指向 TF_Tensor 的指针,该指针具有 TensorBuffer,其本质上被视为一个大小的 void*。

我们可以分解这个问题并为 Java 界面中的每个功能单独提交问题吗? 跟踪/解析会更容易,然后我们可以关闭这个问题。

@drpngx :我的目的是在像我们对 Go 所做的那样关闭之前(从缓冲区读取张量)进行更多更改,并单独提交功能/错误。 所以希望很快。

听起来不错,谢谢!

好吧,似乎我们有足够的基础来构建(例如,足以构建LabelImage 示例,并且人们正在提交更具体的错误/功能请求。

我将关闭这个问题。 Java API 中还有很多工作要做,但让我们在单独的问题中讨论/跟踪它们。 谢谢!

@asimshankar我们正在选择深度学习框架(mxnet/tf),我们的etl/api基于spark/akka流......是否有计划向Java API添加distributed_runtime支持以使用ps运行模型并行训练节点? 对于许多用例来说,ps 节点对我们来说至关重要......javacpp 预设可能更容易在第一次切割时导出,因为 C API 本身似乎没有分布式运行时......

@debasish83Estimator类可以处理很多事情(检查点、摘要保存等)通过 TensorBoard 进行可视化变得简单),这可能使其更适合在 Python 中运行训练作业。

所有这些都可以使用 Java API 中的现有原语来构建,但正确的方法将取决于您的确切需求。

也许我们应该在线程外同步?

@asimshankar tensorflow Java绑定是否已经有一种方法可以从graphDef(从磁盘上的图形的.pb文件构建)中检索信息,例如节点列表、输入和输出格式,还是传入特性? 谢谢!

@asimshankar我不确定使用 TF Java 进行培训时缺少什么。 是数字库的问题(缺少numpy)吗? 我的意思是,如果您对 TensorBoard dataviz 不感兴趣,而只是训练,使用原生 Java 数字库,为什么只使用 python 进行训练(正如您对Estimator类的建议)?

谢谢。

Java中训练模型的状态是什么? 我一直在考虑编写一个 ImageJ(流行和免费的图像分析套件)插件来应用诸如https://arxiv.org/pdf/1505.04597.pdf (最近在细胞跟踪和生物医学应用的图像分割中非常流行)之类的方法。 我认为提供一系列预先训练的模型并使用户能够针对他们的特定用例改进这些模型会很有用。 为此,我一直在研究 DL4J。 是否有任何具体计划允许适应 TF Java 绑定?

@bergwerf :Java 培训当然是可能的,如果不是特别方便的话。
您可以在https://github.com/tensorflow/models/tree/master/samples/languages/java/training找到示例

(另外,我确定您知道,但另请参阅 https://imagej.net/TensorFlow)

哦,真棒! 我的信息必须过时了;-)。 我以为我读过
某处 Java API 仅用于通过预训练进行预测
楷模。 我会研究这个例子。

2018 年 3 月 28 日,星期三,22:01,Asim Shankar通知@ github.com 写道:

@bergwerf https://github.com/bergwerf :Java 培训肯定是
可能,如果不是特别方便的话。
您可以在以下位置找到示例
https://github.com/tensorflow/models/tree/master/samples/languages/java/training


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/tensorflow/tensorflow/issues/5#issuecomment-377015867
或静音线程
https://github.com/notifications/unsubscribe-auth/AEQJ1UD9-xACQAII5996ees_UFJ_NzL-ks5ti-wSgaJpZM4Getd8
.

@asimshankar太棒了 👍 💯 🥇 ,我要添加到我的仓库https://github.com/loretoparisi/tensorflow-java

此页面是否有帮助?
0 / 5 - 0 等级