在NVIDIA(CUDA,CUBLAS)和Intel MKL上快速实现BERT推理

直接在NVIDIA(CUDA,CUBLAS)或Intel MKL上进行高度定制和优化的BERT推理,而无需tensorflow及其框架开销。

仅支持BERT(转换器)。

基准测试

环境

  • Tesla P4
  • 28 * Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz
  • Debian GNU/Linux 8 (jessie)
  • gcc (Debian 4.9.2-10+deb8u1) 4.9.2
  • CUDA: release 9.0, V9.0.176
  • MKL: 2019.0.1.20181227
  • tensorflow: 1.12.0
  • BERT: seq_length = 32

注意:应该在下面运行MKLOMP_NUM_THREADS=?来控制其线程号。其他环境变量及其可能的值包括:

  • KMP_BLOCKTIME=0
  • KMP_AFFINITY=granularity=fine,verbose,compact,1,0

混合精度

NVIDIA Volta和Turing GPU上的Tensor Core 和Mixed Precision可以加速cuBERT 。支持混合精度作为存储在fp16中的变量,并在fp32中进行计算。与单精度推理相比,典型的精度误差小于1%,而速度则达到了2倍以上的加速度。

API

API .h标头

Pooler

支持以下2种pooling方法。

  • 标准BERT pooler,定义为:

with tf.variable_scope("pooler"):

# We "pool" the model by simply taking the hidden state corresponding

# to the first token. We assume that this has been pre-trained

first_token_tensor = tf.squeeze(self.sequence_output[:, 0:1, :], axis=1)

self.pooled_output = tf.layers.dense(

first_token_tensor,

config.hidden_size,

activation=tf.tanh,

kernel_initializer=create_initializer(config.initializer_range))

  • Simple average pooler:

self.pooled_output = tf.reduce_mean(self.sequence_output, axis=1)

输出量

支持以下输出:

从源构建Build from Source

mkdir build && cd build

# if build with CUDA

cmake -DCMAKE_BUILD_TYPE=Release -DcuBERT_ENABLE_GPU=ON -DCUDA_ARCH_NAME=Common ..

# or build with MKL

cmake -DCMAKE_BUILD_TYPE=Release -DcuBERT_ENABLE_MKL_SUPPORT=ON ..

make -j4

# install to /usr/local

# it will also install MKL if -DcuBERT_ENABLE_MKL_SUPPORT=ON

sudo make install

也将安装MKL

如果想运行tfBERT_benchmark进行性能比较,首先从https://www.tensorflow.org/install/lang_c安装tensorflow C API 。

运行单元测试

从 Dropbox下载BERT测试模型bert_frozen_seq32.pb和vocab.txt,然后将它们放在dir下build,运行make test or ./cuBERT_test

thread

Cython提供的简单Python包装器,可以按如下所示在C ++构建之后构建和安装:

cd python

python setup.py bdist_wheel

# install

pip install dist/cuBERT-xxx.whl

# test

python cuBERT_test.py

cuBERT_test.py中检查Python API的用法和示例,获取更多详细信息。

Java

Java包装器是通过JNA实现的 。安装maven和C ++构建后,可以按以下步骤构建:

cd java

mvn clean package # -DskipTests

当使用Java JAR,需要指定jna.library.path的位置libcuBERT.so,如果没有安装到系统路径。并且jna.encoding应像-Djna.encoding=UTF8 JVM启动脚本中一样设置为UTF8 。

ModelTest.java中检查Java API的用法和示例,获取更多详细信息。

安装

可以按以下方式安装预构建的python二进制软件包(当前仅在Linux上与MKL一起安装):

  • 下载MKL并将其安装到系统路径。
  • 下载wheel package包, pip install cuBERT-xxx-linux_x86_64.whl
  • 运行python -c 'import libcubert'以验证安装。

相依性Dependency

Protobuf

cuBERT是使用protobuf-c构建的,以避免版本和代码与tensorflow protobuf冲突。

CUDA

CUDA编译具有不同版本的库不兼容。

MKL

MKL是动态链接的。使用sudo make install安装cuBERT和MKL 。

Threading

假设cuBERT的典型用法是在线服务,其中应尽快处理不同batch_size的并发请求。因此,吞吐量和延迟应保持平衡,尤其是在纯CPU环境中。

vanilla class Bert类Bert由于其内部用于计算的缓冲区而不是线程安全的,因此 编写了wrapper class BertM来保存不同Bert实例的锁,以确保线程安全。 BertM会以循环方式选择一个基础Bert实例,并且同一Bert实例的结果请求可能会被其相应的锁排队。

显卡

一个Bert放在一张GPU卡上。最大并发请求数是一台计算机上可用的GPU卡数量,CUDA_VISIBLE_DEVICES如果指定,则可以控制该数量。

CPU

对于纯CPU环境,它比GPU更复杂。有2个并行级别:

  1. 请求级别。如果在线服务器本身是多线程的,并发请求将竞争CPU资源。如果服务器是单线程的(例如Python中的某些服务器实现),事情将会变得容易得多。
  2. 操作级别。矩阵运算由OpenMP和MKL并行化。最大并行被控制OMP_NUM_THREADS, MKL_NUM_THREADS和许多其他的环境变量。建议用户首先阅读在多线程应用程序中使用线程化英特尔MKL 和建议的设置以从多线程应用程序中调用英特尔MKL例程 。

因此,引入CUBERT_NUM_CPU_MODELS,更好地控制请求级别并行性的方法。此变量指定Bert在CPU /内存上创建的实例数,其作用类似于CUDA_VISIBLE_DEVICESGPU。

  • 如果CPU核心数量有限(旧的或台式机CPU,或在Docker中),则无需使用CUBERT_NUM_CPU_MODELS。例如4个CPU内核,请求级并行度为1,操作级并行度为4,应该可以很好地工作。
  • 但是,如果有许多CPU核心(例如40),则最好尝试使用5的请求级并行度和8的操作级并行度。

总而言之,OMP_NUM_THREADS或MKL_NUM_THREADS定义一个模型可以使用多少个线程,并CUBERT_NUM_CPU_MODELS定义总共有多少个模型。

同样,每个请求的延迟和总体吞吐量应该保持平衡,并且与model seq_length,batch_sizeCPU核心,服务器QPS和许多其他事情有所不同。应该采用很多基准来实现最佳折衷。

在NVIDIA(CUDA,CUBLAS)和Intel MKL上快速实现BERT推理的更多相关文章

  1. Intel MKL函数,如何得到相同的计算结果?【转】

    在运行程序时,我们总希望多次运行的结果,是完全一致,甚至在不同的机器与不同的OS中,程序运行的结果每一位都完全相同. 事实上,程序往往很难保证做到这一点. 为什么呢? 我们先看一个简单的例子: 当程序 ...

  2. [笔记] 基于nvidia/cuda的深度学习基础镜像构建流程

    基于NVidia开源的nvidia/cuda image,构建适用于DeepLearning的基础image. 思路就是先把常用的东西都塞进去,再装某个框架就省事儿了. 为了体验重装系统的乐趣,所以采 ...

  3. Intel MKL(Math Kernel Library)

    1.Intel MKL简介 Intel数学核心函数库(MKL)是一套高度优化.线程安全的数学例程.函数,面向高性能的工程.科学与财务应用.英特尔 MKL 的集群版本包括 ScaLAPACK 与分布式内 ...

  4. ubuntu配置机器学习环境(四) 安装intel MKL

    在这一模块可以选择(ATLAS,MKL或者OpenBLAS),我这里使用MKL,首先下载并安装英特尔® 数学内核库 Linux* 版MKL,下载链接, 请下载Student版,先申请,然后会立马收到一 ...

  5. Intel MKL 多线程设置

    对于多核程序,多线程对于程序的性能至关重要. 下面,我们将对Intel MKL 有关多线程方面的设置做一些介绍: 我们提到MKL 支持多线程,它包括的两个概念:1>MKL 是线程安全的: MKL ...

  6. [笔记] 基于nvidia/cuda的深度学习基础镜像构建流程 V0.2

    之前的[笔记] 基于nvidia/cuda的深度学习基础镜像构建流程已经Out了,以这篇为准. 基于NVidia官方的nvidia/cuda image,构建适用于Deep Learning的基础im ...

  7. 【神经网络与深度学习】【C/C++】比较OpenBLAS,Intel MKL和Eigen的矩阵相乘性能

    比较OpenBLAS,Intel MKL和Eigen的矩阵相乘性能 对于机器学习的很多问题来说,计算的瓶颈往往在于大规模以及频繁的矩阵运算,主要在于以下两方面: (Dense/Sparse) Matr ...

  8. 容器内安装nvidia,cuda,cudnn

    /var/lib/docker/overlay2 占用很大,清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录 du -hs /var/lib/docker/ 命令查看磁盘使用 ...

  9. NVIDIA Turing Architecture架构设计(上)

    NVIDIA Turing Architecture架构设计(上) 在游戏市场持续增长和对更好的 3D 图形的永不满足的需求的推动下, NVIDIA 已经将 GPU 发展成为许多计算密集型应用的世界领 ...

随机推荐

  1. hdu4280 最大流DINIC

    题意:       x最小的到x最大的点同一时间的最大运输量. 思路:       裸的最大流,不解释,注意一点,记得加上防爆栈. #pragma comment(linker, "/STA ...

  2. hdu1914 稳定婚姻问题

               稳定婚姻问题就是给你n个男的,n个女的,然后给你每个男生中女生的排名,和女生心目中男生的排名,然后让你匹配成n对,使婚姻稳定,假如a和b匹配,c和d匹配,如果a认为d比b好,同时 ...

  3. hdu 5059 判断数字表示方式以及范围合法(int型之内)

    题意:       给你一个串和两个整数a,b,问你这个串表示的数字是否合法,并且在a,b之间, 和法的要求是无论是正数还是负数都没有前导0,并且注意 -0 是不合法的. 思路:       写了将近 ...

  4. hdu 3265 线段树扫描线(拆分矩形)

    题意:        给你n个矩形,每个矩形上都有一个矩形的空洞,所有的矩形都是平行于x,y轴的,最后问所有矩形的覆盖面积是多少. 思路:       是典型的矩形覆盖问题,只不过每个矩形上多了一个矩 ...

  5. Shiro反序列化漏洞复现

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企 ...

  6. nodejs-Buffer(缓冲区)

    Node.js Buffer(缓冲区) JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了一个 ...

  7. 四次挥手中你还不知道的ACK机制

    为面试做准备中. 后面有对ACK机制的详细讲解. 四次挥手比较好解释. 看一下我的草图. ACK表示发来的数据已确认接收无误. 图中一个箭头代表一次挥手. 第一次挥手: 主动关闭方:发送一个FIN,表 ...

  8. 【pytest系列】- pytest测试框架介绍与运行

    如果想从头学起pytest,可以去看看这个系列的文章! https://www.cnblogs.com/miki-peng/category/1960108.html 前言​ ​ 目前有两种纯测试的测 ...

  9. (邹博ML)数学分析与概率论

    机器学习入门 深度学习和机器学习? 深度学习在某种意义上可以认为是机器学习的一个分支,只是这个分支非常全面且重要,以至于可以单独作为一门学科来进行研究. 回忆知识 求解S. 对数函数的上升速度 我们使 ...

  10. python主线程捕获子线程异常

    python内置threading.Thread类创建的子线程抛出的异常无法在主线程捕获,可以对该类进行优化,为子线程添加exit code属性,主线程通过获取子线程的返回状态,来判断子线程中是否发生 ...