【问题标题】:Access Tensorflow from Tomcat on CentOS Linux在 CentOS Linux 上从 Tomcat 访问 TensorFlow
【发布时间】:2018-03-31 21:41:46
【问题描述】:

我有一个Java demo working,它使用 Tensorflow 进行图像分类。它在 Windows 上运行良好,但现在我想将它作为来自 Java Tomcat Web 服务器的 Web 服务运行。

我已将所有 Tensorflow jar 添加到 Tomcat 的库中,但 Tensorflow 具有 jni 依赖项。我不确定如何安装和链接它,以便 Tensorflow 可以在 CentOS Linux 服务器上运行。

I have read this,但我不需要在服务器上运行python,只需从Java访问Tensorflow即可。

更新:**好的,要让它在 Windows 上的 Tomcat 上运行,我执行以下操作,

从下载 libtensorflow.jar, https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.6.0.jar

然后是来自的 dll, https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-windows-x86_64-1.6.0.zip (解压zip获取dll)

见,https://www.tensorflow.org/install/install_java

将jar放入我的tomcat lib中,并创建一个tomcat dll目录并将dll放入其中

编辑我的 setenv.bat 并添加该行,

SET CATALINA_OPTS=-Xmx4g -XX:PermSize=128m -XX:MaxPermSize=512m -Djava.library.path=D:\Engineering\apache-tomcat-7.0.50\dll

这适用于 Windows。

对于 Linux、CentOS 6,我也这样做,但不是从 dll 下载 so 文件, https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-linux-x86_64-1.6.0.tar.gz

并编辑我的 setenv.sh 并添加行,

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/tomcat8/so"
export JAVA_OPTS="-server -Xmx38g -Djava.library.path=/usr/local/tomcat8/so"
export CATALINA_OPTS="-Djava.library.path=/usr/local/tomcat8/so"

但这些似乎都不起作用,我总是收到错误,

找不到适用于操作系统的 TensorFlow 本机库:linux,架构: x86_64。看 https://github.com/tensorflow/tensorflow/tree/master/tensorflow/java/README.md 寻找可能的解决方案(例如从源代码构建库)。 有关尝试查找本机库的其他信息可以是 通过向系统添加 org.tensorflow.NativeLibrary.DEBUG=1 获得 JVM 的属性。

我发现还有另一个部署选项,只需添加 jar,

到lib,它会神奇地找到正确的so文件。

https://mvnrepository.com/artifact/org.tensorflow/libtensorflow_jni

当我尝试这个选项时,它似乎找到了 so 文件,但我得到了这个错误,

/usr/local/tomcat8/temp/tensorflow_native_libraries-1522357321965-0/libtensorflow_jni.so:/lib64/libc.so.6:未找到版本“GLIBC_2.16”(/usr/local/tomcat8/temp 需要/tensorflow_native_libraries-1522357321965-0/libtensorflow_jni.so)

好像 Tensorflow 只支持特定的操作系统和版本??

我发现了这个, Error while importing Tensorflow in python2.7 in Ubuntu 12.04. 'GLIBC_2.17 not found'

但尚未尝试任何选项。对于生产系统来说,看起来没有希望。

看GLIBC是什么,是给GPU的,但是我没有也不需要用GPU,只想用CPU,为什么需要这个库??

** 更新 所以...我尝试在 Centos6 上构建 glibc 1.6.0,以便我可以通过以下方式使用它,

https://unix.stackexchange.com/questions/176489/how-to-update-glibc-to-2-14-in-centos-6-5

这些步骤有效,但在尝试运行 Tensorflow 时会导致此错误,似乎它依赖于另一个库...

加载共享库时出错:__vdso_time: invalid mode for dlopen()

此时我准备放弃,尝试安装 Centos7,但这条路线需要我们升级 12 台生产服务器...

【问题讨论】:

  • 您必须像在 Windows 上一样提供 jni 库。库必须放置在您使用-Djava.library.path=... 指定的路径上。唯一的区别:库被命名为lib.so,而不是lib.dll。您的问题和链接都没有告诉我们哪个库。所以我们不能告诉你要安装哪个包。
  • @James 你的项目是 maven 的吗?
  • 不,没有 maven,运行 tomcat 应用程序被部署到 tomcat webapps,所有 jar 都在 tomcat/lib 中,所以文件在 tomcat/so 中 - 问题是 tomcat 似乎没有收到所以路径,或者tensorflow不喜欢so文件
  • @James 我已经更新了答案,还包括在 linux 上托管的专用 tomcat Web 服务器的设置
  • 更新后的帖子出现新错误,未找到“GLIBC_2.16”

标签: java linux tomcat tensorflow


【解决方案1】:

嗯,我对 Java 中的 tensorflow 知之甚少。但是,我确实做了一些研究,并相信我得出了解决您问题的结论。

当然,如果您阅读@Igor 的解决方案,您在Error while importing Tensorflow in python2.7 in Ubuntu 12.04. 'GLIBC_2.17 not found' 中发布的解决方案实际上可以缓解问题。

为了更好地理解这个问题:tensorflow 在 java 中的工作方式是你的包调用 python 库,它在它下面实际上调用 C 代码,这是库的主要核心和力量所在。因此,您可能会将 Java 包视为 Python tensorflow 的包装器,后者是 C 库的包装器。

回想一下,Linux 操作系统是用 C 语言构建的,并且几乎总是将 Glibc 作为系统要求预先安装,如前几行中的here 所述。话虽如此,您面临的问题是 tensorflow 所需的 GLibc 是最新版本,与您的操作系统运行的版本不同。

如果您在此处阅读问题installation problem (version 'GLIBC' 2.14 not found),您会看到运行的操作系统是与您的相同的 Cent OS 的类似问题。该特定问题的唯一区别是相关人员使用的是 python 而不是 java,但问题是相同的。

因此,您有几种可能的方法来解决它。

  1. 在另一个基于 linux 的操作系统上运行您的代码,您的 Glibc 与 tensorflow 兼容(或可以轻松更新)

  2. 全局升级您的系统 GLIBC。如果您在服务器上运行它并且有据可查here,这将非常痛苦。 (据我了解,您可能只需安装 python 即可解决此问题。抱歉,我没有完整阅读这篇文章)。

  3. 向您的系统添加第二个 GLIBC(风险)

  4. 从源代码编译 Glibc 和 Bazel。 (听起来像是第一个选项之后最合理的解释)

  5. 按照@Igor 在post 中的建议,从源代码编译 tensorflow 以处理您当前的 glibc。我不知道这是否可行,因为我不确定 tensorflow 库可能调用了哪些 C 功能。

我希望这个回复至少没什么帮助。干杯!

【讨论】:

  • 我认为除了升级操作系统之外没有其他好的选择。 Centos 7 于 2014 年发布,从 6.x 线转移是一个好主意,迟早要完成。要使软件与旧 GLIBC 一起工作,几乎需要使用旧 GCC,但它可能无法编译现代/最新的 Tensorflow 代码。
  • 我同意,几个月后 tensorflow 可能需要越来越多的更新。截至目前,Centos 7.4 使用 glibc 2.17 并且将是最快的修复。您仍然需要执行您已经使用 Centos 6 完成的步骤,但总比重新设计所有内容要好。
【解决方案2】:

这个问题与 Java 没有直接关系,都是关于旧的好 C 和本地库的链接。发生了什么(简而言之):

  1. Tensorflow 的 Java 库通过 JNI(Java 本地接口)对本地库进行运行时调用
  2. 这个原生库(.jar 中的 .so 文件)是在比 Centos6 更“新鲜”的 Linux 发行版下编译的,可能是在 Ubuntu LTS 下,这就是为什么它与更新鲜的 glibc 库版本相关联。

手动更新 glibc 并保持系统稳定没有简单的方法,所以最好升级到 CentOS 7,它已经安装了所需的 glibc 版本: https://rpmfind.net/linux/rpm2html/search.php?query=libc.so.6%28GLIBC_2.16%29%2864bit%29&submit=Search+...&system=centos&arch=

【讨论】:

    【解决方案3】:

    我只是仔细看了看。

    简单地将org.tensorflow:tensorflow:1.4.0-rc0(或您喜欢的任何版本)添加到您最喜欢的构建工具。

    这将引入对org.tensorflow:libtensorflow_jni:1.4.0-rc0 的依赖。这将包括以下内容:

    blafasel@localhost:~$ unzip -t .m2/repository/org/tensorflow/libtensorflow_jni/1.4.0-rc0/libtensorflow_jni-1.4.0-rc0.jar
    Archive:  .m2/repository/org/tensorflow/libtensorflow_jni/1.4.0-rc0/libtensorflow_jni-1.4.0-rc0.jar
        testing: META-INF/                OK
        testing: META-INF/MANIFEST.MF     OK
        testing: org/                     OK
        testing: org/tensorflow/          OK
        testing: org/tensorflow/native/   OK
        testing: org/tensorflow/native/darwin-x86_64/   OK
        testing: org/tensorflow/native/linux-x86_64/   OK
        testing: org/tensorflow/native/windows-x86_64/   OK
        testing: org/tensorflow/native/darwin-x86_64/libtensorflow_framework.so   OK
        testing: org/tensorflow/native/darwin-x86_64/LICENSE   OK
        testing: org/tensorflow/native/darwin-x86_64/libtensorflow_jni.dylib   OK
        testing: org/tensorflow/native/linux-x86_64/libtensorflow_framework.so   OK
        testing: org/tensorflow/native/linux-x86_64/libtensorflow_jni.so   OK
        testing: org/tensorflow/native/linux-x86_64/LICENSE   OK
        testing: org/tensorflow/native/windows-x86_64/tensorflow_jni.dll   OK
        testing: org/tensorflow/native/windows-x86_64/LICENSE   OK
        testing: META-INF/maven/          OK
        testing: META-INF/maven/org.tensorflow/   OK
        testing: META-INF/maven/org.tensorflow/libtensorflow_jni/   OK
        testing: META-INF/maven/org.tensorflow/libtensorflow_jni/pom.xml   OK
        testing: META-INF/maven/org.tensorflow/libtensorflow_jni/pom.properties   OK
    No errors detected in compressed data of .m2/repository/org/tensorflow/libtensorflow_jni/1.4.0-rc0/libtensorflow_jni-1.4.0-rc0.jar.
    

    正如您所见,它已经包含了所有需要的二进制文件,以使 JNI 在所有官方支持的平台上运行。包含 x86_64 上的任何 Linux。

    只要您不尝试在 raspi 或 32 位 CentOS 上使用它,并且只要您使用合适的构建工具,就应该保存。

    唯一的风险在于这些库依赖于其他系统库。在libtensorflow_framework.so 上调用ldd 显示:

    blafasel@localhost:~$ ldd org/tensorflow/native/linux-x86_64/libtensorflow_framework.so
        linux-vdso.so.1 =>  (0x00007ffffaa62000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f07c6494000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f07c6290000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f07c6073000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f07c5cf0000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f07c5ada000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f07c5710000)
        /lib64/ld-linux-x86-64.so.2 (0x000056525c661000)
    

    如果你没有在你的系统上找到这些传递依赖,你可能应该尝试旧版本的 tensorflow 或更新的 CentO。

    【讨论】:

      【解决方案4】:

      免责声明

      请考虑这个答案更长,因为它回答了最初发布的问题,以及随着通过 cmets 和讨论提供更多信息而演变而来的其他问题。

      更新 2:

      提供的新信息表明,centOS6 服务器上的 glibc 版本比编译 tensorflow 二进制文件的 glibc 版本旧。要将 CentOS6 服务器上的 glibc 版本更新到较新的版本,您可以尝试此升级脚本 (credit to origin) 中描述的步骤。

      我建议升级整个服务器,而不是只升级glibc

      您当前服务器上的许多其他命令都是针对您当前的 glibc 版本编译的。如果您对该库进行升级,您可能会遇到兼容性问题,这可能会导致服务器一起损坏。

      #! /bin/sh
      
      # update glibc to 2.17 for CentOS 6
      
      wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-2.17-55.el6.x86_64.rpm
      wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-common-2.17-55.el6.x86_64.rpm
      wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-devel-2.17-55.el6.x86_64.rpm
      wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-headers-2.17-55.el6.x86_64.rpm
      
      sudo rpm -Uvh glibc-2.17-55.el6.x86_64.rpm \
      glibc-common-2.17-55.el6.x86_64.rpm \
      glibc-devel-2.17-55.el6.x86_64.rpm \
      glibc-headers-2.17-55.el6.x86_64.rpm
      

      原答案:

      有一个jar文件包含tensorflow的JNI分布。

      您可以使用与tensorflow.jar 匹配的版本(在您的情况下为1.6.0)简单地下载tensorflow_jni.jar,并将其与您的应用程序一起打包。 JNI jar 将位于类路径中,并会被自动拾取。

      您也可以将tensorflow_jni.jar 复制粘贴到tomcat 的lib 文件夹中。

      tensorflow_jni.jar是为CPU使用配置的,如果你想使用GPU,你可以downloadtensorflow_jni_gpu.jar代替。

      演示:

      我已经制作了一个演示应用程序,它作为 war 包部署到专用的 Tomcat 8.5.29,带有一个打印 tensorflow 版本的 rest 端点,我可以确认提供 tensorflow.jartensorflow_jni.jar 都有效,无需任何额外的配置或调整。

      我已将测试应用程序上传到my github account。您可以查看它,将其打包为一个 war 文件(mvn package 或任何您用来执行此操作的文件)并将其部署到 Tomcat 中。

      按照描述打包它需要maven,但在这种情况下maven的主要目的是下载pom文件中声明的必要依赖项。

      如果您不想使用 maven,您可以从上面提供的链接手动下载依赖项并将它们合并到您的应用程序设置中。

      更新 - 在专用 Tomcat 中配置本机库

      这是我使用专用 Tomcat8 进行设置的方法,其中所有 tensorflow 依赖项都在 Web 服务器中配置,而不是随部署的应用程序一起提供。

      1)这是我的 war 依赖项的样子 - 它有 0 个 tensorflow 依赖项:

      为了在链接的项目中生成它,您只需将 tensorflow 依赖项标记为 pom.xml 中提供的内容:

      <dependency>
          <groupId>org.tensorflow</groupId>
          <artifactId>tensorflow</artifactId>
          <version>1.6.0</version>
          <scope>provided</scope> <!-- add this line -->
      </dependency>
      

      并从目标目录中提取demo-tensorflow-0.0.1-SNAPSHOT.war.original 战争(在部署到 tomcat 之前删除 .original)。

      2)这是文件系统上SO文件的路径,反映了您指定的路径:

      3) Tomcat 的 lib 文件夹:

      4) 如果我在 tomcat 中部署 war 包并尝试访问其余端点,我将得到与您相同的错误:

      5)我在 CATALINA_BASE 中创建了setenv.sh(为了清楚起见,我只在 CATALINA_OPTS 中添加了库路径)。

      export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/tomcat8/so"
      export JAVA_OPTS="-server -Xmx38g"
      export CATALINA_OPTS="-Djava.library.path=/usr/local/tomcat8/so"
      

      然后

      chmod u+x setenv.sh
      

      6) 运行 tomcat 我可以在日志消息中看到配置被拾取:

      7)本次访问应用成功:

      【讨论】:

      • tensorflow 有不同的 lib 依赖项/so 文件,这取决于你想要 gpu 还是 cpu 支持,这个 lib jar 使用哪一个?
      • 我已经更新了我的答案 - tensorflow_jni.jar 是 CPU 配置的,tensorflow_jni_gpu.jar 是 GPU 配置的。
      • 感谢所有帮助,但它仍然对我不起作用,我更新了上面的帖子,无论我做什么我都会得到相同的所以没有发现错误,即使它显示了等等路径和你一样
      • 如果我尝试找到正确的单个 jar,那么它似乎会尝试加载 so 但给出链接错误,/usr/local/tomcat8/temp/tensorflow_native_libraries-1522357321965-0/libtensorflow_jni .so:/lib64/libc.so.6:找不到版本“GLIBC_2.16”(/usr/local/tomcat8/temp/tensorflow_native_libraries-1522357321965-0/libtensorflow_jni.so 需要)
      • 使用 centos 6,tensorflow 是否只适用于非常特定的操作系统和版本?
      猜你喜欢
      • 1970-01-01
      • 2015-01-24
      • 2010-12-06
      • 1970-01-01
      • 2023-03-20
      • 2013-06-26
      • 1970-01-01
      • 2016-05-03
      • 2016-08-20
      相关资源
      最近更新 更多