自动文本摘要经典模型TextSum运行录(四):显卡环境
1 反思环境错误
之前的bazel编译命令中如果加入cuda参数--config=cuda
,那么会报以下的错误:
Starting local Bazel server and connecting to it...
INFO: Options provided by the client:
Inherited 'common' options: --isatty=1 --terminal_columns=109
ERROR: Config value cuda is not defined in any .rc file
INFO: Invocation ID: 390be6f9-4be2-4963-aa95-8c848261ba40
其中Config value cuda is not defined in any .rc file
是一个十分经典的问题,GitHub上有很多issue在讨论它,比如这条。网上最主要的统一的意见就是bazel的版本太高,与tensorflow不兼容。于是我换成了tensorflow-1.0.0
对应的bazel版本。然后发现Error只是变成了warning,程序自动略去了处理不了的参数,这没有任何帮助。
然后当我去掉这个参数的时候,出现了找不到cudart-8.0.so
之类的错误,我才意识到问题的严重性,GPU版本的tensorflow有某种机制指出了其所需的CUDA版本,一旦找不到对应版本,就通不过内部的Assertion。因为这里所依赖的CUDA不是每个用户每个虚拟环境可以装多个的,所以为了使用GPU跑模型,需要让模型代码的版本适应平台。
2 修改运行环境
$ cat /home/intern/cuda-9.0/version.txt
$ cat /home/intern/cuda-9.0/include/cudnn.h | grep "#define CUDNN_MAJOR"
使用以上命令查看实验室服务器上的CUDA和CUDNN环境版本,可以看到结果分别为如下:
CUDA Version 9.0.176
#define CUDNN_MAJOR 7
这说明CUDA的版本为9,而CUDNN的版本为7。我们可以查看官方文档:从源代码构建-经过测试的构建配置。其中操作系统为linux,运行方式为GPU的版本信息如下:
在我的服务器配置下,为了照顾代码的兼容性,最低可用的tensorflow版本为tensorflow_gpu-1.5.0
。你可以直接使用pip命令安装:
$ pip install tensorflow-gpu==1.5.0
对应的,我们需要构建工具的版本为Bazel 0.8.0
,你可以从官方的Github上下载:bazel-0.8.0-installer-linux-x86_64.sh。下载好以后,使用chmod +x ...sh
为其添加执行权限,然后bash执行它。这时普通用户可能会由于权限问题出现无法创建文件的报错,你需要顺着提示加入参数--user
:
$ bash bazel-0.8.0-installer-linux-x86_64.sh --user
这样它会把bazel安装在/home/user/.bin/
目录下。我们无法删除系统已经安装的bazel,但是我们可以修改~/.bashrc
中的bazel路径,使新的bazel将旧的覆盖。然后使用命令bazel version
测试一下。如果出现了warning,版本显示的还是老的版本,那么可能是因为现在还有老的bazel的进程没有执行完毕。那也无所谓我们可以在使用bazel命令的时候带着它的绝对路径。
我们将原来的textsum
模型拷贝一份,重命名为Textsum_gpu
。注意删除train_log
、bazel-out
和textsum/log_root
,否则模型容易报错。我们进入新配置的conda虚拟环境,继续执行带有cuda参数的构建命令:
$ /home/user/bazel build -c opt --config=cuda textsum/...
但这是我们会得到与上文提到的完全一样的问题,我在这时又陷入了绝望。仔细阅读了多个issue后(虽然它们描述的问题和我不一样),我意识到我的rc文件应该指的是/home/user/.bazelrc
这个文件。我打开这个文件发现它是空的,我恍然大悟,所以它才说rc中没有定义cuda。
我参考了一些使用tensorflow源码编译的博客,然后发现他们时常会遇到这个问题:
WARNING: The following rc files are no longer being read, please transfer their contents or import their path into one of the standard rc files:
/home/user/tensorflow/tools/bazel.rc
我后来也尝试了源码编译tensorflow,只能说错误百出。但我发现在tensorflow的源码中,tool文件夹下开始时有一个rc文件的template,当你随着./configure
命令指定了配置后,就会生成一个正式的bazel.rc。然后Warning就来了,它提示你要将bazel.rc文件的内容拷贝到别的地方去。于是我看了一下这个模板文件,它大概长这样:
build:cuda aaa@qq.com_config_cuda//crosstool:toolchain
build:cuda --define=using_cuda=true --define=using_cuda_nvcc=true
build:cuda_clang aaa@qq.com_config_cuda//crosstool:toolchain
build:cuda_clang --define=using_cuda=true --define=using_cuda_clang=true
build:win-cuda --define=using_cuda=true --define=using_cuda_nvcc=true
build:mkl --define=using_mkl=true
build:sycl aaa@qq.com_config_sycl//crosstool:toolchain
build:sycl --define=using_sycl=true --define=using_trisycl=false
build:sycl_nodouble aaa@qq.com_config_sycl//crosstool:toolchain
build:sycl_nodouble --define=using_sycl=true --cxxopt -DTENSORFLOW_SYCL_NO_DOUBLE
build:sycl_asan aaa@qq.com_config_sycl//crosstool:toolchain
build:sycl_asan --define=using_sycl=true --define=using_trisycl=false --copt -fno-omit-frame-pointer --copt -fsanitize-coverage=3 --copt -DGPR_NO_DIRECT_SYSCALLS --linkopt -fPIC --linkopt -fsanitize=address
build:sycl_trisycl aaa@qq.com_config_sycl//crosstool:toolchain
build:sycl_trisycl --define=using_sycl=true --define=using_trisycl=true
build --define=use_fast_cpp_protos=true
build --define=allow_oversize_protos=true
build --define=grpc_no_ares=true
build --spawn_strategy=standalone
build --genrule_strategy=standalone
build -c opt
实际上,我并不知道@local_config_cuda
和@local_config_sycl
等变量占位符的值究竟应该是多少,所以我也不关心。事实证明,将其中第二行:
build:cuda --define=using_cuda=true --define=using_cuda_nvcc=true
添加到/home/user/.bazelrc
中即可消除之前的找不到cuda定义的错误。
注意事项!!! 实际上我们可以不用bazel编译,虽然这是官网上的教程,我们直接使用:
$ python textsum/seq2seq_attention.py [options]
一样是可以运行的,可能使用bazel构建后,用java虚拟机跑会更快更稳定一些吧。
3 代码优化加速
3.1 去除过时代码
之前运行代码的时候总会提示:
WARNING:tensorflow:: Using a concatenated state is slower and will soon be deprecated. Use state_is_tuple=True.
后来我发现这个参数是tf.contrib.rnn.LSTMCell
的,需要修改seq2seq_attention_model.py
,一共有3处。修改后自然可以提高速度。以其中一处为例:
cell = tf.contrib.rnn.LSTMCell(
hps.num_hidden,
initializer=tf.random_uniform_initializer(-0.1, 0.1, seed=113),
state_is_tuple=False # 修改为state_is_tuple=True
)
3.2 Train使用GPU
在我首次运行模型时参考的博客:How to Run Text Summarization with TensorFlow 中指出了训练时,程序未使用GPU的问题。我阅读过代码,当然清楚,作者预留了一张显卡作为特殊用处。所以说如果用单卡的服务器跑程序,会将唯一的GPU保留下来不使用。我很想改代码,但又不敢贸然行动,万一预留是有什么特殊目的的呢?
这条issue:textsum --num_gpus=1 #356 中的某个评论指出了修改后的代码可以正常使用。只需要将原始的seq2seq_attention_model.py
中的下文:
self._cur_gpu = (self._cur_gpu + 1) % (self._num_gpus-1)
修改为如下,解决除零错误:
self._cur_gpu = (self._cur_gpu + 1) % (self._num_gpus-1 if self._num_gpus > 1 else self._num_gpus)
然后在运行模型的时候加上参数--num_gpus=1
即可。经过试验,我的模型可以一下子使用80%的GPU。接下来就希望我不会出现显存溢出的问题啦。GPU跑这个模型的速度可以提升几十倍。当前运行模型的命令:
$ nohup bazel-bin/textsum/seq2seq_attention \
--mode=train \
--article_key=article \
--abstract_key=abstract \
--data_path=data/train \
--vocab_path=data/vocab \
--log_root=textsum/log_root \
--train_dir=textsum/log_root/train \
--max_run_steps=100000 \
--num_gpus=1 \
> train_log 2>&1 &
$ nohup tensorboard --logdir=textsum/log_root 2>&1 &
3.3 调整学习率
下面是我之前使用CPU跑的模型的running_avg_loss
,可以看出它收敛很慢,且上下波动严重。我认为是由于学习率偏高导致梯度下降时矫枉过正。我当前的学习率是0.15,是嵌入在代码中的死值。下一步就是让学习率对命令行参数开放,多进行几次小规模的预实验,找到一个稳定的参数。这一切都建立在模型可以使用GPU运行的基础上。
上一篇: python练习题3.4:星号三角形
下一篇: 第十四周作业