自动文本摘要经典模型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与CUDA的版本对应表

在我的服务器配置下,为了照顾代码的兼容性,最低可用的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 --crosstool_top=@local_config_cuda//crosstool:toolchain
build:cuda --define=using_cuda=true --define=using_cuda_nvcc=true

build:cuda_clang --crosstool_top=@local_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 --crosstool_top=@local_config_sycl//crosstool:toolchain
build:sycl --define=using_sycl=true --define=using_trisycl=false

build:sycl_nodouble --crosstool_top=@local_config_sycl//crosstool:toolchain
build:sycl_nodouble --define=using_sycl=true --cxxopt -DTENSORFLOW_SYCL_NO_DOUBLE

build:sycl_asan --crosstool_top=@local_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 --crosstool_top=@local_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运行的基础上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值