Java / Tensorflow - API 调用 pb 模型使用 GPU 推理

Posted BIT_666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java / Tensorflow - API 调用 pb 模型使用 GPU 推理相关的知识,希望对你有一定的参考价值。

目录

一.引言

二.Java / Tensorflow 代码配置

1.代码配置

2.Maven 配置

三.环境检测

1.显卡检测

2.显卡监控

四.推理踩坑

1.异常现象

2.异常日志

五.安装 cuda-10.0

1.下载 cuda 安装包

2.安装 cuda

2.1 preface 前言

2.2 安装配置

2.3 安装完成

2.4 可能遇到的问题

六.安装 cuDNN

1.安装 cuDNN

2.解压 tgz 文件

3.查看 cuDNN 版本

七.使用 cuda-10.0 推理

八.总结


一.引言

使用 Java Tensorflow API 调用 pb 模型执行推理逻辑,之前一直使用 CPU,近期尝试 GPU 推理,下面记录一下踩坑的过程。

二.Java / Tensorflow 代码配置

1.代码配置

      // GPU 使用配置
      val gpuConfig = GPUOptions.newBuilder()
        .setVisibleDeviceList("0")
        .setForceGpuCompatible(true)
        .setAllowGrowth(true)
        .build()

      // Tensorflow 模型加载配置
      val configproto = ConfigProto.newBuilder()
        .setGpuOptions(gpuConfig)
        .setInterOpParallelismThreads(op)
        .setIntraOpParallelismThreads(op)
        .build()

使用 GPU 还是 CPU 在代码配置阶段主要差别于是否在 configproto 中增加 GpuOptions,GPUOptions 需要单独使用 builder 初始化:

AllowGrouwth: 是否预先分配整个指定的 GPU 内存区域,如果为 True 则按需增长

ForceGpuCompatible: 启用此选项会强制所有 CPU 张量分配有 Cuda 固定内存,对于较大模型不推荐

VisibleDeviceList: 指定 GPU 设备,一般从0开始,例如 /device:GPU:0,也可以逗号分隔指定多台,例如 "0,1,2,3"

2.Maven 配置

tensorflow 基础依赖

        <dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>tensorflow</artifactId>
            <version>1.15.0</version>
            <scope>provided</scope>
        </dependency>

这里正常情况下 CPU 推理使用下面的版本依赖,如果使用 GPU 需使用 jni_gpu 版本: 

        // GPU
        <dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>libtensorflow_jni_gpu</artifactId>
            <version>1.15.0</version>
            <scope>provided</scope>
        </dependency>
        // CPU
        <dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>libtensorflow_jni</artifactId>
            <version>1.15.0</version>
            <scope>provided</scope>
        </dependency>

三.环境检测

1.显卡检测

在使用 Java x Tensorflow x GPU 推理时,首先需要确保自己的显卡配置成功,可以在对应环境下执行下述 python 代码,确保 GPU 配置成功:

from tensorflow.python.client import device_lib

device_lib.list_local_devices()

执行后如果出现下述样例日志,代表 GPU 环境配置无误,可以看到这里是 Device-0,这里 0 和上面的  VisibleDeviceList 对应,可以制定该参数为 "0",使用该显卡。

确定环境无误后,下面开始踩坑 GPU 推理过程。

2.显卡监控

可以使用 nvidia-smi 命令检测显卡显存与利用率:

如果运行任务,可以使用 watch 命令,固定间隔实时更新显卡使用率,-n 代表频率,1代表1s,执行命令后,bash 上会每s更新一次上图的显卡指标:

watch -n 1 nvidia-smi

四.推理踩坑

pom 修改为 GPU 对应依赖,代码也增加 GPUOptions 后,开始了第一次测试。

1.异常现象

任务可执行,但执行期间显卡监控只有显存的增加而 GPU-Util 利用率 始终为 0,怀疑是模型加载到显存中,但是由于某些原因模型无法使用 GPU 推理所以出现如下情况:

2.异常日志

查看模型加载的日志才发现有如下异常,无法加载 cuda10.0.so xxxx 类似的报错:

2022-09-27 10:58:21.077390: I tensorflow/cc/saved_model/reader.cc:31] Reading SavedModel from: /root/xudong/3fe686d2-59e1-4821-b5a3-baa79d0d53b8
2022-09-27 10:58:21.110117: I tensorflow/cc/saved_model/reader.cc:54] Reading meta graph with tags  serve 
2022-09-27 10:58:21.136320: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 AVX512F FMA
2022-09-27 10:58:21.144301: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2600000000 Hz
2022-09-27 10:58:21.145011: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7f3c00495c00 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2022-09-27 10:58:21.145065: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2022-09-27 10:58:21.146331: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcuda.so.1
2022-09-27 10:58:21.158831: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1618] Found device 0 with properties:
name: Tesla V100-PCIE-32GB major: 7 minor: 0 memoryClockRate(GHz): 1.38
pciBusID: 0000:21:02.0
2022-09-27 10:58:21.158971: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcudart.so.10.0'; dlerror: libcudart.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.159037: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcublas.so.10.0'; dlerror: libcublas.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.159092: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcufft.so.10.0'; dlerror: libcufft.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.159150: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcurand.so.10.0'; dlerror: libcurand.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.159203: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcusolver.so.10.0'; dlerror: libcusolver.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.159259: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'libcusparse.so.10.0'; dlerror: libcusparse.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/cuda-11.2/lib64/:/usr/local/cuda/targets/x86_64-linux/lib/:/usr/local/hadoop-2.7.3/lib/native/:/usr/local/jdk1.8.0_131/jre/lib/amd64/server/
2022-09-27 10:58:21.162605: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2022-09-27 10:58:21.162628: W tensorflow/core/common_runtime/gpu/gpu_device.cc:1641] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.
Skipping registering GPU devices...
2022-09-27 10:58:21.283803: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1159] Device interconnect StreamExecutor with strength 1 edge matrix:
2022-09-27 10:58:21.283842: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1165]      0
2022-09-27 10:58:21.283850: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1178] 0:   N
2022-09-27 10:58:21.366089: I tensorflow/cc/saved_model/loader.cc:202] Restoring SavedModel bundle.
2022-09-27 10:58:21.572327: I tensorflow/cc/saved_model/loader.cc:151] Running initialization op on SavedModel bundle at path: /root/xudong/3fe686d2-59e1-4821-b5a3-baa79d0d53b8
2022-09-27 10:58:21.641867: I tensorflow/cc/saved_model/loader.cc:311] SavedModel load for tags  serve ; Status: success. Took 564483 microseconds.

上面报错比较多,主要的报错是这句 Could not load dynamic library 'libcudart.so.10.0' :

Could not load dynamic library 'libcudart.so.10.0'; dlerror: libcudart.so.10.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/jdk1.8.0_131/jre/lib/amd64/server:/usr/local/jdk1.8.0_131/jre/lib/amd64:/usr/local/jdk1.8.0_131/jre/../lib/amd64:/usr/local/

即无法加载对应 cuda 的 so 文件,so 文件可以看做是 c++ 封装好的 java API,支持 JAVA 调用。回看上面显卡的监控情况,CUDA Version 为 11.4,这里加载 so.10.0,肯定异常,所以需要安装 cuda-10.0,且支持双环境。

五.安装 cuda-10.0

1.下载 cuda 安装包

打开 CUDA 官网,由于上面报错无法加载 so.10.0,所有这里下载 10.0 对应版本,博主这里使用 linux 环境,下面选项分别为 Linux + x86_64 + CentOS + 7 + runFile(local):

 待下载完成后,会获得一个 cuda_10.0.130_410.48_linux.run 文件

2.安装 cuda

博主 cuda 安装在 /usr/local 目录下,所以可以直接将  cuda_10.0.130_410.48_linux.run 文件移动至 /usr/lcoal 下:

执行下述命令:

sudo sh cuda_10.0.130_410.48_linux.run --override

2.1 preface 前言

执行安装后几s内会弹出 preface 相关的序言,这里按 'q' 继续即可:

2.2 安装配置

第一个选项必须 accept,否则安装会直接退出

第二个选项安装显卡驱动,我们前边检验已经通过,所以 n 否

第三个选项安装 cuda 工具包 ,必须的 y

第四个安装地址,默认 /usr/local/cuda-10.0 enter 回车即可,也可以自定义位置

第五个安装 cuda 环境,由于我们默认环境为 cuda 11.x 所以这里选择 n 否,否则会覆盖原有环境,如果你没有 cuda 环境,y 即可

第六个是否安装 cuda 样例,y、n 均可

最后一个选项即样例的位置,可以 enter 回车默认,也可以自定义

选择完毕后,会出现 Installing the CUDA .... 提示,代表开始安装。

2.3 安装完成

 出现如上日志即代表安装成功,可以看到 /local/usr 目录下也出现 cuda-10,0 的文件夹:

2.4 可能遇到的问题

安装期间可能出现报错并退出,提示用户到 /var/log/nvidia-installer.log 目录下查看安装异常日志:

通过查看日志分析原因,安装期间所在机器 GPU 不能处于使用期间,如果 GPU 使用期间安装会导致安装失败,因为 Dirver 需要 upgrade,所以安装期间需要保证 GPU 未使用,可以使用 top 命令查看相关任务的 pid,并 kill 掉对应 pid 保证 GPU 不再使用。

六.安装 cuDNN

CUDA 是 NVIDIA 推出的运算平台,cuDNN 是用于深度网络的 GPU 加速库,可以支持 GPU 实现高性能并行计算。

1.安装 cuDNN

进入cuDNN 官网 可以选择对应版本的 cuDNN,博主上述采用 cuda 10.0 + linux:

这里下载需要注册邮箱,比较麻烦,大家也可以在这里选中版本在网上搜索直接下载即可。 将得到的下载文件后缀修改为 tgz 得到:

cudnn-10.0-linux-x64-v7.4.1.5.tgz

2.解压 tgz 文件

	tar -xvf cudnn-10.0-linux-x64-v7.4.1.5.tgz

解压 cudnn 文件得到 cuda 文件夹: 

 继续执行 cp 命令,将 cuda 中的文件拷贝至刚才安装的 cuda-11.0 的文件夹中:

cp cuda/lib64/* /usr/local/cuda-10.0/lib64/
cp cuda/include/* /usr/local/cuda-10.0/include/
chmod a+r /usr/local/cuda-10.0/lib64/*
chmod a+r /usr/local/cuda-10.0/include/*

3.查看 cuDNN 版本

cat /usr/local/cuda-10.0/include/cudnn.h | grep CUDNN_MAJOR -A2

出现下述日志即安装成功: 

七.使用 cuda-10.0 推理

由于我并未未将 cuda-10.0 设置为环境变量,因此如果 shell 脚本中使用 cuda-10.0 需指定对应目录:

export CUDA_DIR="/usr/local/cuda-10.0/"

在 shell 中 export CUDA_DIR 即可指定至所需环境,使用其他 CUDA 环境同理,如果不添加则默认使用环境变量下的 CUDA-11.x。此时再次执行推理任务不再出现无法加载 so.10.0 相关日志,而是 Successfully opened so.10.0 xxx,代表前面安装成功,并且成功加载了 device-0。

 再次查看显卡监控:

可以看到在显存占用的情况下,GPU 利用率也不再是 0%,大功告成!

八.总结

Java x Tensorflow x GPU 踩坑大致就这么多,一般来说推理还是用 python 或者 c++ 更方便一些,如果使用 java API ,可以参考如下表格选择 cuda 版本:

以上是关于Java / Tensorflow - API 调用 pb 模型使用 GPU 推理的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow学习(十七):高级API之tf.layers

用 Python 生成的 Tensorflow 数据集在 Tensorflow Java API(标签图像)中有不同的读数

Java / Tensorflow - API 调用 pb 模型使用 GPU 推理

Tensorflow:模型调参

Tensorflow 模型的超参数调优

13 Tensorflow API主要功能