10859 在 glibc < 2.17 的系统上安装 TensorFlow

  目前,TensorFlow 依赖于 glibc 2.17 以上的版本。但在有些超级计算机集群上,操作系统比较老旧,glibc 的版本达不到要求,但一般用户又没有权限升级。在一般情况下,用户可以把这种被依赖的软件安装到自己的 home 目录下,并把软件的安装目录添加到 LD_LIBRARY_PATH 环境变量中。但 glibc 是非常底层的库,贸然把新版本加入 LD_LIBRARY_PATH,容易导致与系统的其它组件不兼容。不兼容的后果可能是十分严重的,比如导致简单的 ls 命令都失效。为了绕过对 glibc 的要求,也可以从 TensorFlow 的源码开始手工编译、安装,但这个过程也费时费力,且成功率低。

  前几天,我成功地研究出了在 glibc < 2.17 的系统上安装并运行 TensorFlow 的方法,在此分享一下,希望能帮到遇到类似困难的朋友。

  我的 Linux 系统为 CentOS 6.5,64 位,glibc 版本为 2.12。我安装的 TensorFlow 是带 GPU 支持的,如果你不需要 GPU,则需要自行修改某些步骤。

《10859 在 glibc < 2.17 的系统上安装 TensorFlow》

一、安装 TensorFlow

  第一步,是先假装 glibc 的版本问题不存在,暴力安装 TensorFlow。为此,你需要首先安装 Python,我推荐 AnacondaMiniconda 版本。

  安装好 Python 后,执行如下命令安装最新版的 TensorFlow:

pip install --upgrade tensorflow-gpu

  如果中途遇到「找不到 easy_install」的错误,那么请先执行如下命令安装 setuptools,再安装 TensorFlow:

pip install --upgrade setuptools

  安装完 TensorFlow 后,在 Python 里面 import tensorflow as tf,应该会出现将近一屏的报错信息,其中有如下字句:

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found

虽然这里只说需要 glibc 2.16,但实际上是需要 2.17 的。下面,我们就来安装 glibc 2.17。

《10859 在 glibc < 2.17 的系统上安装 TensorFlow》

二、安装 glibc 2.17

  glibc 的各个版本都可以从这里下载。我安装的是最低限的 2.17 版,你也可以安装更高的版本,但我没有测试过。

  首先新建一个你希望下载、安装 glibc 的目录,并 cd 到那里去。然后执行下列命令:

wget http://mirror.rit.edu/gnu/libc/glibc-2.17.tar.gz
tar zxvf glibc-2.17.tar.gz
mkdir glibc-2.17-build glibc-2.17-install
cd glibc-2.17-build
../glibc-2.17/configure --prefix=`readlink -f ../glibc-2.17-install`
make -j 8
make -j 8 install

这段命令会下载 glibc 2.17 的源码,并解压到 glibc-2.17 目录中。然后,它会在 glibc-2.17-build 目录中编译 glibc,并安装到 glibc-2.17-install 目录中。glibc 要求编译不能直接在源码目录中进行,所以我才新建了 glibc-2.17-build 目录;文章开头说过 glibc 容易与系统的其它组件不兼容,所以我专门创建了 glibc-2.17-install 这个安装目录,而没有把它安装到 $HOME/usr/local 里去。

  glibc 的编译安装可能花费半个小时至一个小时,请耐心等待。安装完毕之后,你会在 glibc-2.17-install 目录下看到 bin、lib 等目录。把 lib 目录定义成一个环境变量 GLIBC_DIR,备用:

export GLIBC_DIR=<...>/glibc-2.17-install/lib

这行代码最好也加到~/.bashrc里去,这样就永远可以使用GLIBC_DIR这个环境变量了。

《10859 在 glibc < 2.17 的系统上安装 TensorFlow》

三、调用新版 glibc

注:这不是一个必须的步骤,它主要是为了解释第四步中命令的原理;你也可以用它来确认一下 glibc 已经正确安装。

  调用新版 glibc 并不是一件简单的事情。经过重重摸索,我终于找到了调用它的正确姿势:

$GLIBC_DIR/ld-2.17.so --library-path $GLIBC_DIR:/lib64:$LD_LIBRARY_PATH <command>

  我来解释一下这行命令。$GLIBC_DIR/ld-2.17.so 是个可执行程序(对,虽然它带着 .so 扩展名,看起来仿佛是个库),由它去执行后面的 <command> 命令。--library-path 指明了执行命令时可以调用的库,它包括三部分:

  • $GLIBC_DIR:刚刚安装的新版 glibc;
  • /lib64:包含一些系统核心的库;
  • $LD_LIBRARY_PATH:你本来能调用的、自定义的库。

一个不方便的地方是,<command> 必须是可执行文件的完整路径;换句话说,ld-2.17.so 不会去 $PATH 里查找。例如,你直接用 ls 代替 <command> 是不行的,必须写 /bin/ls。但有一个投机取巧的方法是用 `which ls`代替 <command>,由 which 命令来查找ls所在的位置。

  上面这条命令中的--library-path参数,也可以用环境变量来替代:

LD_LIBRARY_PATH=$GLIBC_DIR:/lib64:$LD_LIBRARY_PATH $GLIBC_DIR/ld-2.17.so <command>

用这条命令执行ls,可以达到同样的效果。但这种用法有一个潜在的问题:如果被执行的<command>命令又调用了其它程序,那么环境变量LD_LIBRARY_PATH会继续起作用,但ld-2.17.so则不起作用了,导致不兼容。若使用本节开头的用法,那么<command>命令调用的其它程序则不受这两者中任一者的影响,可以调用老版 glibc 正常运行。

  本节开头的命令中的任何一部分都是必不可少的,缺少则会导致各种错误(也许你已经见过了呢)。例如:

  • 不使用$GLIBC_DIR/ld-2.17.so,仅设置LD_LIBRARY_PATH环境变量,会导致如下错误:
    • error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
  • 省略--library-path中的$GLIBC_DIR,会导致 segmentation fault;
  • 省略--library-path中的/lib64,会导致如下错误:
    • error while loading shared libraries: libselinux.so.1: cannot open shared object file: No such file or directory

《10859 在 glibc < 2.17 的系统上安装 TensorFlow》

四、在新版 glibc 下运行 TensorFlow

  在~/.bashrc中定义一个 alias tfpython

alias tfpython="$GLIBC_DIR/ld-2.17.so --library-path $GLIBC_DIR:/lib64:$LD_LIBRARY_PATH `which python`"

然后执行之:

CUDA_VISIBLE_DEVICES=<gpuid> tfpython

注意我多设置了一个环境变量CUDA_VISIBLE_DEVICES,这是为了告诉 Tensorflow 可以使用几号 GPU。

  进入 Python 后,执行如下的命令来测试 TensorFlow:

import tensorflow as tf
tf.Session().run(tf.constant('Hello World!'))

如果一切正常,你应该看到几条提示信息,以及运行结果Hello World!

  如果遇到「找不到 cuDNN 6.0」的报错信息,那么你需要到 NVidia 网站下载 cuDNN 6.0(需要注册),把它解压到某个地方(会解压出一个名为 cuda 的目录),然后在~/.bashrc中设置如下的环境变量:

export CUDNN_INCLUDE_DIR="<...>/cuda/include"
export CUDNN_LIBRARY_PATH="<...>/cuda/lib64"
export CUDNN_LIBRARY="$CUDNN_LIBRARY_PATH/libcudnn.so.6"
export LD_LIBRARY_PATH="$CUDNN_LIBRARY_PATH:$LD_LIBRARY_PATH"

  如果遇到「找不到 libcuda」的报错信息,那么你需要用locate libcuda命令找到 libcuda 所在的目录(例如/usr/lib64),并在~/.bashrc中把这个目录添加到LD_LIBRARY_PATH中去:

export LD_LIBRARY_PATH="/usr/lib64:$LD_LIBRARY_PATH"

  确认 TensorFlow 正常运行之后,我们还要确认一下使用了新版 glibc 的 Python 仍然能够调用其它程序:

import os
os.system('ls')

如果在 Python 中执行上述命令能够看到当前目录的内容,则说明 Python 仍能正常调用其它程序。这些其它程序是完全在老版 glibc 下运行的,不受新版 glibc 影响。

    原文作者:王赟 Maigo
    原文地址: https://zhuanlan.zhihu.com/p/33059558
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞