引用:https://arleyzhang.github.io/articles/7f4b25ce/
1 簡介
TensorRT是一個高性能的深度學習推理(Inference)優化器,可以為深度學習應用提供低延遲、高吞吐率的部署推理。TensorRT可用於對超大規模數據中心、嵌入式平台或自動駕駛平台進行推理加速。TensorRT現已能支持TensorFlow、Caffe、Mxnet、Pytorch等幾乎所有的深度學習框架,將TensorRT和NVIDIA的GPU結合起來,能在幾乎所有的框架中進行快速和高效的部署推理。
TensorRT 是一個C++庫,從 TensorRT 3 開始提供C++ API和Python API,主要用來針對 NVIDIA GPU進行 高性能推理(Inference)加速。現在最新版TensorRT是4.0版本。
TensorRT 之前稱為GIE。
關於推理(Inference):
由以上兩張圖可以很清楚的看出,訓練(training)和 推理(inference)的區別:
- 訓練(training)包含了前向傳播和后向傳播兩個階段,針對的是訓練集。訓練時通過誤差反向傳播來不斷修改網絡權值(weights)。
- 推理(inference)只包含前向傳播一個階段,針對的是除了訓練集之外的新數據。可以是測試集,但不完全是,更多的是整個數據集之外的數據。其實就是針對新數據進行預測,預測時,速度是一個很重要的因素。
一般的深度學習項目,訓練時為了加快速度,會使用多GPU分布式訓練。但在部署推理時,為了降低成本,往往使用單個GPU機器甚至嵌入式平台(比如 NVIDIA Jetson)進行部署,部署端也要有與訓練時相同的深度學習環境,如caffe,TensorFlow等。
由於訓練的網絡模型可能會很大(比如,inception,resnet等),參數很多,而且部署端的機器性能存在差異,就會導致推理速度慢,延遲高。這對於那些高實時性的應用場合是致命的,比如自動駕駛要求實時目標檢測,目標追蹤等。
所以為了提高部署推理的速度,出現了很多輕量級神經網絡,比如squeezenet,mobilenet,shufflenet等。基本做法都是基於現有的經典模型提出一種新的模型結構,然后用這些改造過的模型重新訓練,再重新部署。
而tensorRT 則是對訓練好的模型進行優化。 tensorRT就只是 推理優化器。當你的網絡訓練完之后,可以將訓練模型文件直接丟進tensorRT中,而不再需要依賴深度學習框架(Caffe,TensorFlow等),如下:
可以認為tensorRT是一個只有前向傳播的深度學習框架,這個框架可以將 Caffe,TensorFlow的網絡模型解析,然后與tensorRT中對應的層進行一一映射,把其他框架的模型統一全部 轉換到tensorRT中,然后在tensorRT中可以針對NVIDIA自家GPU實施優化策略,並進行部署加速。
目前TensorRT4.0 幾乎可以支持所有常用的深度學習框架,對於caffe和TensorFlow來說,tensorRT可以直接解析他們的網絡模型;對於caffe2,pytorch,mxnet,chainer,CNTK等框架則是首先要將模型轉為 ONNX 的通用深度學習模型,然后對ONNX模型做解析。而tensorflow和MATLAB已經將TensorRT集成到框架中去了。
ONNX(Open Neural Network Exchange )是微軟和Facebook攜手開發的開放式神經網絡交換工具,也就是說不管用什么框架訓練,只要轉換為ONNX模型,就可以放在其他框架上面去inference。這是一種統一的神經網絡模型定義和保存方式,上面提到的除了tensorflow之外的其他框架官方應該都對onnx做了支持,而ONNX自己開發了對tensorflow的支持。從深度學習框架方面來說,這是各大廠商對抗谷歌tensorflow壟斷地位的一種有效方式;從研究人員和開發者方面來說,這可以使開發者輕易地在不同機器學習工具之間進行轉換,並為項目選擇最好的組合方式,加快從研究到生產的速度。
上面圖中還有一個 Netwok Definition API 這個是為了給那些使用自定義的深度學習框架訓練模型的人提供的TensorRT接口。舉個栗子:比如 YOLO 作者使用的darknet要轉tensorrt估計得使用這個API,不過一般網上有很多使用其他框架訓練的YOLO,這就可以使用對應的caffe/tensorflow/onnx API了。
ONNX / TensorFlow / Custom deep-learning frame模型的工作方式:
現在tensorRT支持的層有:
- Activation: ReLU, tanh and sigmoid
- Concatenation : Link together multiple tensors across the channel dimension.
- Convolution: 3D,2D
- Deconvolution
- Fully-connected: with or without bias
- ElementWise: sum, product or max of two tensors
- Pooling: max and average
- Padding
- Flatten
- LRN: cross-channel only
- SoftMax: cross-channel only
- RNN: RNN, GRU, and LSTM
- Scale: Affine transformation and/or exponentiation by constant values
- Shuffle: Reshuffling of tensors , reshape or transpose data
- Squeeze: Removes dimensions of size 1 from the shape of a tensor
- Unary: Supported operations are exp, log, sqrt, recip, abs and neg
- Plugin: integrate custom layer implementations that TensorRT does not natively support.
基本上比較經典的層比如,卷積,反卷積,全連接,RNN,softmax等,在tensorRT中都是有對應的實現方式的,tensorRT是可以直接解析的。
但是由於現在深度學習技術發展日新月異,各種不同結構的自定義層(比如:STN)層出不窮,所以tensorRT是不可能全部支持當前存在的所有層的。那對於這些自定義的層該怎么辦?
tensorRT中有一個 Plugin 層,這個層提供了 API 可以由用戶自己定義tensorRT不支持的層。 如下圖:
這就解決了適應不同用戶的自定義層的需求。
2 優化方式
TentsorRT 優化方式:
TensorRT優化方法主要有以下幾種方式,最主要的是前面兩種。
-
層間融合或張量融合(Layer & Tensor Fusion)
如下圖左側是GoogLeNetInception模塊的計算圖。這個結構中有很多層,在部署模型推理時,這每一層的運算操作都是由GPU完成的,但實際上是GPU通過啟動不同的CUDA(Compute unified device architecture)核心來完成計算的,CUDA核心計算張量的速度是很快的,但是往往大量的時間是浪費在CUDA核心的啟動和對每一層輸入/輸出張量的讀寫操作上面,這造成了內存帶寬的瓶頸和GPU資源的浪費。TensorRT通過對層間的橫向或縱向合並(合並后的結構稱為CBR,意指 convolution, bias, and ReLU layers are fused to form a single layer),使得層的數量大大減少。橫向合並可以把卷積、偏置和激活層合並成一個CBR結構,只占用一個CUDA核心。縱向合並可以把結構相同,但是權值不同的層合並成一個更寬的層,也只占用一個CUDA核心。合並之后的計算圖(圖4右側)的層次更少了,占用的CUDA核心數也少了,因此整個模型結構會更小,更快,更高效。
-
數據精度校准(Weight &Activation Precision Calibration)
大部分深度學習框架在訓練神經網絡時網絡中的張量(Tensor)都是32位浮點數的精度(Full 32-bit precision,FP32),一旦網絡訓練完成,在部署推理的過程中由於不需要反向傳播,完全可以適當降低數據精度,比如降為FP16或INT8的精度。更低的數據精度將會使得內存占用和延遲更低,模型體積更小。
如下表為不同精度的動態范圍:
Precision | Dynamic Range |
---|---|
FP32 | −3.4×1038 +3.4×1038−3.4×1038 +3.4×1038 |
FP16 | −65504 +65504−65504 +65504 |
INT8 | −128 +127−128 +127 |
INT8只有256個不同的數值,使用INT8來表示 FP32精度的數值,肯定會丟失信息,造成性能下降。不過TensorRT會提供完全自動化的校准(Calibration )過程,會以最好的匹配性能將FP32精度的數據降低為INT8精度,最小化性能損失。關於校准過程,后面會專門做一個探究。
-
Kernel Auto-Tuning
網絡模型在推理計算時,是調用GPU的CUDA核進行計算的。TensorRT可以針對不同的算法,不同的網絡模型,不同的GPU平台,進行 CUDA核的調整(怎么調整的還不清楚),以保證當前模型在特定平台上以最優性能計算。
TensorRT will pick the implementation from a library of kernels that delivers the best performance for the target GPU, input data size, filter size, tensor layout, batch size and other parameters.
-
Dynamic Tensor Memory
在每個tensor的使用期間,TensorRT會為其指定顯存,避免顯存重復申請,減少內存占用和提高重復使用效率。
-
Multi-Stream Execution
Scalable design to process multiple input streams in parallel,這個應該就是GPU底層的優化了。
3 安裝
這里 是英偉達提供的安裝指導,如果有仔細認真看官方指導,基本上按照官方的指導肯定能安裝成功。
問題是肯定有很多人不願意認真看英文指導,比如說我就是,我看那個指導都是直接找到命令行所在,直接敲命令,然后就出了很多問題,然后搜索好長時間,最后才發現,原來官方install guide里是有說明的。
這里使用的是 deb 包安裝的方式,以下是安裝過程,我是cuda 8.0 ,cuda9.0也是類似的。
進行下面三步時最好先將后面記錄的遇到的問題仔細看看,然后回過頭來按照 一二三 步來安裝。
第一步:
1
2
3
4
|
|
其中的deb包要換成與自己 cuda和系統 對應的版本。
第二步:
使用python2則安裝如下依賴
1
|
|
這個是為了安裝一些依賴的:比如 python-libnvinfer python-libnvinfer-dev swig3.0
如果是python3則安裝如下依賴
1
|
|
第三步:
1
|
|
這個是安裝通用文件格式轉換器,主要用在 TensorRT 與TensorFlow 交互使用的時候。
不過我安裝的時候還是出問題了:
-
安裝tensorRT之前要將cuda的兩個deb包添加上,因為TensorRT依賴好多cuda的一些東西比如
cuda-cublas-8-0
,我之前cuda是用runfile安裝的,所以TensorRT安裝時有些依賴庫找不到導致出錯,如下圖:
上面提示缺少依賴包,但是實際上
libnvinfer4
的包是tensorRT安裝了之后才有的,那現在反而成了依賴包了,不管他,缺什么安裝什么,但是還是出錯,如下:
哇,還是缺少依賴包,這次是缺 cuda-cublas-8-0
,現在知道了,缺的是cuda的相關組件。
后來把 cuda 的兩個deb包安裝之后就沒問題了,cuda 8.0 的deb包 在這里 ,如下圖,下載紅框里的兩個deb包。
如果用的是 runfile 的方式安裝的cuda的話,很容易出錯,因為網上大部分cuda安裝教程都是用runfile的方式安裝的。所以如果cuda就是用deb包安裝的話,就沒有這個問題,如果使用runfile安裝的話,安裝tensorRT之前要把這兩個deb包安裝上,安裝方式如下:
1
2
|
|
以上是自己摸索出來的,折騰了一番之后才發現原來官方的 install guide已經說明了,如下:
The debian installation automatically installs any dependencies, but:
- requires sudo root privileges to install
- provides no flexibility as to which location TensorRT is installed into
- requires that the CUDA Toolkit has also been installed with a debian package.
注意最后一條,意思是如果用deb包安裝TensorRT,那么前提是 你的CUDA也是用deb包安裝的。
怪自己沒有認真看,要是多花個5分鍾仔細看一下,就不用折騰這么久了,由此深有感觸,文檔還是官方英文原版的最好,而且要認真看。
不過不知道用 runfile cuda+Tar File Installation tensorRT的組合安裝方式是怎么樣的,沒試過。
-
tensorRT 3 支持CUDA 8 和 CUDA 9,但是只支持 cuDNN 7,我第一次安裝的時候cuDNN是5.1的,結果總是出錯,錯誤是啥忘記了,反正換成cuDNN 7就好了,這個官方指導也有說明,不過比較隱蔽,他是放在 4.2 Tar File Installation 一節說明的:
- Install the following dependencies, if not already present:
‣ Install the CUDA Toolkit v8.0, 9.0 or 9.2
‣ cuDNN 7.1.3
‣ Python 2 or Python 3
我試過只要大版本是 cudnn7就可以。這個也容易忽略。
- Install the following dependencies, if not already present:
安裝好后,使用 $ dpkg -l | grep TensorRT
命令檢測是否成功,輸出如下所示即為成功
安裝后會在 /usr/src
目錄下生成一個 tensorrt
文件夾,里面包含 bin
, data
, python
, samples
四個文件夾, samples
文件夾中是官方例程的源碼; data
, python
文件中存放官方例程用到的資源文件,比如caffemodel文件,TensorFlow模型文件,一些圖片等;bin
文件夾用於存放編譯后的二進制文件。
可以把 tensorrt
文件夾拷貝到用戶目錄下,方便自己修改測試例程中的代碼。
進入 samples
文件夾直接 make,會在 bin
目錄中生成可執行文件,可以一一進行測試學習。
另外tensorRT是不開源的, 它的頭文件位於 /usr/include/x86_64-linux-gnu
目錄下,共有七個,分別為:
1
2
3
4
5
6
7
|
/usr/include/x86_64-linux-gnu/NvCaffeParser.h
/usr/include/x86_64-linux-gnu/NvInfer.h
/usr/include/x86_64-linux-gnu/NvInferPlugin.h
/usr/include/x86_64-linux-gnu/NvOnnxConfig.h
/usr/include/x86_64-linux-gnu/NvOnnxParser.h
/usr/include/x86_64-linux-gnu/NvUffParser.h
/usr/include/x86_64-linux-gnu/NvUtils.h
|
TensorRT4.0相比於3.0新增了對ONNX的支持。
tensorRT的庫文件位於 /usr/lib/x86_64-linux-gnu
目錄下,如下(篩選出來的,摻雜了一些其他nvidia庫):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/usr/lib/x86_64-linux-gnu/libnvinfer.so
/usr/lib/x86_64-linux-gnu/libnvToolsExt.so
/usr/lib/x86_64-linux-gnu/libnvinfer_plugin.a
/usr/lib/x86_64-linux-gnu/libnvinfer_plugin.so.4
/usr/lib/x86_64-linux-gnu/libnvcaffe_parser.so
/usr/lib/x86_64-linux-gnu/libnvparsers.so.4.1.2
/usr/lib/x86_64-linux-gnu/stubs/libnvrtc.so
/usr/lib/x86_64-linux-gnu/libnvcaffe_parser.a
/usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.1
/usr/lib/x86_64-linux-gnu/libnvvm.so
/usr/lib/x86_64-linux-gnu/libnvinfer.a
/usr/lib/x86_64-linux-gnu/libnvvm.so.3
/usr/lib/x86_64-linux-gnu/libnvToolsExt.so.1
/usr/lib/x86_64-linux-gnu/libnvrtc.so.7.5
/usr/lib/x86_64-linux-gnu/libnvparsers.a
/usr/lib/x86_64-linux-gnu/libnvblas.so.7.5
/usr/lib/x86_64-linux-gnu/libnvToolsExt.so.1.0.0
/usr/lib/x86_64-linux-gnu/libnvcaffe_parser.so.4.1.2
/usr/lib/x86_64-linux-gnu/libnvinfer_plugin.so
/usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so
/usr/lib/x86_64-linux-gnu/libnvparsers.so
/usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.7.5.18
/usr/lib/x86_64-linux-gnu/libnvblas.so.7.5.18
/usr/lib/x86_64-linux-gnu/libnvvm.so.3.0.0
/usr/lib/x86_64-linux-gnu/libnvrtc.so
/usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.7.5
/usr/lib/x86_64-linux-gnu/libnvinfer.so.4.1.2
/usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.390.30
/usr/lib/x86_64-linux-gnu/libnvrtc.so.7.5.17
/usr/lib/x86_64-linux-gnu/libnvblas.so
/usr/lib/x86_64-linux-gnu/libnvinfer.so.4
/usr/lib/x86_64-linux-gnu/libnvparsers.so.4
/usr/lib/x86_64-linux-gnu/libnvinfer_plugin.so.4.1.2
/usr/lib/x86_64-linux-gnu/libnvcaffe_parser.so.4
|
編譯
將 /usr/src/tensorrt
文件夾拷貝到用戶目錄下,假設路徑為 <tensorrt_srcpath>
。
第一個問題:
在 <tensorrt_srcpath>/tensorrt/samples
文件夾中有個 Makefile.config
文件,里面第4行:
1
|
CUDA_VER?=cuda-
$(shell dpkg-query -f '$${version}\n' -W 'cuda-cudart-[0-9]*' | cut -d . -f 1,2 | sort -n | tail -n 1)
|
這一句是為了獲取cuda版本的,我的機器是 CUDA 8.0 。我記得我第一次安裝時,后面dpkg命令 輸出的不是8.0,是一個很奇怪的數字,導致我不能編譯 tensorRT 例程。 后來我直接在這句后面添加了一句: CUDA_VER=cuda-8.0
,簡單粗暴解決問題了。
這個問題好像是還是因為我之前安裝 cuda 時是用 runfile 的方式安裝的,用這種方式安裝的cuda不會安裝cuda的deb包,所以上面語句輸出的是不對的,導致找不到cuda庫目錄,編譯不能進行。
可以使用命令sudo dpkg -i cuda-repo-ubuntu1604-8-0-local-ga2_8.0.61-1_amd64.deb
,安裝deb包,就可以了。或者像我那樣添加 CUDA_VER=cuda-8.0
也可以。
如果安裝cuda就是使用deb包安裝的話,就不會出現這個問題。
第二個問題:
如果機器上安裝了多個cuda版本,像我這個機器上 cuda8.0,9.0,9.1都裝上了,上面語句得到的就只是 CUDA_VER=9.1,如果安裝的是其他版本cuda的TensorRT的話肯定是不對的。
可以直接在第4行下面添加:
1
|
CUDA_INSTALL_DIR=/usr/local/cuda-9.0
|
3 TensorRT 使用流程
這是個很簡單的流程,先簡單了解一下,以后會深入研究更高級的用法。
在使用tensorRT的過程中需要提供以下文件(以caffe為例):
- A network architecture file (deploy.prototxt), 模型文件
- Trained weights (net.caffemodel), 權值文件
- A label file to provide a name for each output class. 標簽文件
前兩個是為了解析模型時使用,最后一個是推理輸出時將數字映射為有意義的文字標簽。
tensorRT的使用包括兩個階段, build and deployment:
- build:Import and optimize trained models to generate inference engines
build階段主要完成模型轉換(從caffe或TensorFlow到TensorRT),在模型轉換時會完成前述優化過程中的層間融合,精度校准。這一步的輸出是一個針對特定GPU平台和網絡模型的優化過的TensorRT模型,這個TensorRT模型可以序列化存儲到磁盤或內存中。存儲到磁盤中的文件稱之為 plan file。
下面代碼是一個簡單的build過程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
//創建一個builder
IBuilder* builder = createInferBuilder(gLogger);
// parse the caffe model to populate the network, then set the outputs
// 創建一個network對象,不過這時network對象只是一個空架子
INetworkDefinition* network = builder->createNetwork();
//tensorRT提供一個高級別的API:CaffeParser,用於解析Caffe模型
//parser.parse函數接受的參數就是上面提到的文件,和network對象
//這一步之后network對象里面的參數才被填充,才具有實際的意義
CaffeParser parser;
auto blob_name_to_tensor = parser.parse(“deploy.prototxt”,
trained_file.c_str(),
*network,
DataType::kFLOAT);
// 標記輸出 tensors
// specify which tensors are outputs
network->markOutput(*blob_name_to_tensor->find(
"prob"));
// Build the engine
// 設置batchsize和工作空間,然后創建inference engine
builder->setMaxBatchSize(
1);
builder->setMaxWorkspaceSize(
1 << 30);
//調用buildCudaEngine時才會進行前述的層間融合或精度校准優化方式
ICudaEngine* engine = builder->buildCudaEngine(*network);
|
上面的過程使用了一個高級別的API:CaffeParser,直接讀取 caffe的模型文件,就可以解析,也就是填充network對象。解析的過程也可以直接使用一些低級別的C++API,比如:
1
2
|
ITensor* in = network->addInput(“input”, DataType::kFloat, Dims3{…});
IPoolingLayer* pool = network->addPooling(in, PoolingType::kMAX, …);
|
解析caffe模型之后,必須要指定輸出tensor,設置batchsize,和設置工作空間。設置batchsize就跟使用caffe測試是一樣的,設置工作空間是進行前述層間融合和張量融合的必要措施。層間融合和張量融合的過程是在調用builder->buildCudaEngine時才進行的。
- deploy:Generate runtime inference engine for inference
deploy階段主要完成推理過程,Kernel Auto-Tuning 和 Dynamic Tensor Memory 應該是在這里完成的。將上面一個步驟中的plan文件首先反序列化,並創建一個 runtime engine,然后就可以輸入數據(比如測試集或數據集之外的圖片),然后輸出分類向量結果或檢測結果。
tensorRT的好處就是不需要安裝其他深度學習框架,就可以實現部署和推理。
以下是一個簡單的deploy代碼:這里面沒有包含反序列化過程和測試時的batch流獲取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
// The execution context is responsible for launching the
// compute kernels 創建上下文環境 context,用於啟動kernel
IExecutionContext *context = engine->createExecutionContext();
// In order to bind the buffers, we need to know the names of the
// input and output tensors. //獲取輸入,輸出tensor索引
int inputIndex = engine->getBindingIndex(INPUT_LAYER_NAME),
int outputIndex = engine->getBindingIndex(OUTPUT_LAYER_NAME);
//申請GPU顯存
// Allocate GPU memory for Input / Output data
void* buffers = malloc(engine->getNbBindings() * sizeof(void*));
cudaMalloc(&buffers[inputIndex], batchSize * size_of_single_input);
cudaMalloc(&buffers[outputIndex], batchSize * size_of_single_output);
//使用cuda 流來管理並行計算
// Use CUDA streams to manage the concurrency of copying and executing
cudaStream_t stream;
cudaStreamCreate(&stream);
//從內存到顯存,input是讀入內存中的數據;buffers[inputIndex]是顯存上的存儲區域,用於存放輸入數據
// Copy Input Data to the GPU
cudaMemcpyAsync(buffers[inputIndex], input,
batchSize * size_of_single_input,
cudaMemcpyHostToDevice, stream);
//啟動cuda核計算
// Launch an instance of the GIE compute kernel
context.enqueue(batchSize, buffers, stream,
nullptr);
//從顯存到內存,buffers[outputIndex]是顯存中的存儲區,存放模型輸出;output是內存中的數據
// Copy Output Data to the Host
cudaMemcpyAsync(output, buffers[outputIndex],
batchSize * size_of_single_output,
cudaMemcpyDeviceToHost, stream));
//如果使用了多個cuda流,需要同步
// It is possible to have multiple instances of the code above
// in flight on the GPU in different streams.
// The host can then sync on a given stream and use the results
cudaStreamSynchronize(stream);
|
可見使用了挺多的CUDA 編程,所以要想用好tensorRT還是要熟練 GPU編程。
4 Performance Results
來看一看使用以上優化方式之后,能獲得怎樣的加速效果:
可見使用tensorRT與使用CPU相比,獲得了40倍的加速,與使用TensorFlow在GPU上推理相比,獲得了18倍的加速。效果還是很明顯的。
以下兩圖,是使用了INT8低精度模式進行推理的結果展示:包括精度和速度。
來自:GTC 2017,Szymon Migacz 的PPT
可見精度損失很少,速度提高很多。
上面還是17年 TensorRT2.1的性能,這里 是一個最新的TensorRT4.0.1的性能表現,有很詳細的數據展示來說明TensorRT在inference時的強勁性能。
后面的博客中會進一步學習 tensorRT,包括官方例程和做一些實用的優化。
參考資料
- What’s the Difference Between Deep Learning Training and Inference?
- Discover the Difference Between Deep Learning Training and Inference
- GTC 2017,Szymon Migacz 的PPT
- NVIDIA TensorRT | NVIDIA Developer
- Deploying Deep Neural Networks with NVIDIA TensorRT
- TensorRT 3: Faster TensorFlow Inference and Volta Support
- tensorRT installation guide
- cuda installation guide
- NVIDIA TensorRT Performance Guide
- TensorRT 4 Accelerates Neural Machine Translation, Recommenders, and Speech
- ONNX