欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自动文本摘要经典模型TextSum运行录(四):显卡环境

程序员文章站 2022-07-01 18:19:15
...

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的版本信息如下:

自动文本摘要经典模型TextSum运行录(四):显卡环境

在我的服务器配置下,为了照顾代码的兼容性,最低可用的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_logbazel-outtextsum/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运行的基础上。

自动文本摘要经典模型TextSum运行录(四):显卡环境