使用 NVIDIA TensorRT 進行 BERT 即時自然語言處理

作者 NVIDIA

本文章最初於 2019 8 月發表現已針對 NVIDIA TensorRT 8.0 進行更新。

BERT、GPT-2、XL-Net 等大規模語言模型,為許多自然語言處理(natural language processing,NLP)任務的準確度帶來令人期待的躍進。自 2018 年 10 月發布至今,BERT(Bidirectional Encoder Representations from Transformers,來自 Transformer 的雙向編碼器表示)及其眾多變體仍是最熱門的語言模型之一,且仍可提供最先進的準確度

BERT 在 NLP 任務之準確度方面的大躍進,為許多產業之公司帶來以語言為基礎的高品質服務。想要實際使用模型,就必須考量延遲、準確度等,會影響終端使用者對服務之滿意度的因素。由於是採用 12/24 層堆疊多頭注意力網路,致使 BERT 在推論過程中需要進行大量運算。 因此,企業很難將 BERT 部署為即時應用程式的一部分。

近期 NVIDIA 發布 TensorRT 第 8 版,將 NVIDIA A100 GPU 上的 BERT-Large 推論延遲降低至 1.2 毫秒,並將以 transformer 為基礎之網路進行最新的最佳化。TensorRT 最新廣義的最佳化可以加快所有此類模型,將推論時間減少至 TensorRT 7 版的一半。

TensorRT

TensorRT 是用於高效能深度學習推論的平台,包括最佳化工具和執行階段、最小化延遲,以及最大化傳輸量。您可以利用 TensorRT 最佳化在所有主要框架中訓練的模型,以高準確度校正較低的精度,並最終部署於實際應用中。

使用 BERT 實現此效能的所有程式碼,在此 NVIDIA/TensorRT GitHub 儲存庫中已發布為開放原始碼。 我們已最佳化 BERT 編碼器之基礎構件的轉換器層,您可以將這些最佳化應用於任何以 BERT 為基礎的 NLP 任務上。除對話式 AI 外,BERT 適用於更多的語音和 NLP 應用程式,所有的這些應用程式都能利用這些最佳化。

問答(question answering,QA)或閱讀理解是測試模型理解脈絡之能力的常用方式。SQuAD 排行榜會記錄此任務之最高效能模型提供的資料集和測試集。在最近幾年,QA 能力因學術界和業界的全球貢獻,而獲得快速進步。

本文示範了如何使用 Python 建立簡單的 QA 應用程式,並搭載 NVIDIA 所發布的 TensorRT 最佳化 BERT 程式碼。此範例為 API 提供輸入段落和問題,並回傳 BERT 模型產生的回應。

以下簡要說明使用 TensorRT for BERT 執行訓練和推論的步驟。

BERT 訓練和推論工作流程

NLP 研究人員和開發人員面臨的主要問題,為缺乏特定 NLP 任務的高品質有標籤訓練資料。為了克服針對任務從零開始學習模型的問題,NLP 突破使用大量的無標籤文字,並將 NLP 任務分為兩部分:

  • 學習表示單字的含義、單字之間的關係,亦即是使用輔助任務和大型文字語料庫建立語言模型
  • 透過相對較小、以監督方式訓練的任務專用網路擴增語言模型,在實際任務中,將語言模型專門化。

上述兩個階段通常稱為預先訓練和微調。此範式可以將預先訓練語言模型運用於各種任務中,而無須針對模型架構進行任何任務專用變更。在此範例中,BERT 提供了可以針對 QA 進行微調,但是適用於句子分類、情緒分析等其他任務的高品質語言模型。

您可以從線上提供的預先訓練檢查點開始,或在本身的自訂語料庫上預先訓練 BERT(圖 1)。您也可以從檢查點啟動預先訓練,然後在自訂資料上繼續進行訓練。

BERT TensorRT engine generation chart. A pretrained checkpoint or a checkpoint pretrained on custom data can be used as input to the TensorRT Builder, which creates the optimized engine as output.
1:從預先訓練檢查點產生 BERT TensorRT 引擎

使用自訂或領域專用資料進行預先訓練,可能會產生有趣的結果,例如 BioBert。但是這樣運算密集需求,需要大規模的平行運算基礎架構,才能在合理的時間內完成。在此類情境中,採用 GPU 之多節點訓練是理想的解決方案。欲深入瞭解 NVIDIA 開發人員如何在一小時以內訓練 BERT,請參閱使用 GPU 訓練 BERT

在微調步驟中使用任務專用訓練資料,訓練以預先訓練 BERT 語言模型為基礎的任務專用網路。微調對運算的需求通常遠低於預先訓練。

想要使用 QA 神經網路執行推論:

  1. 將經過微調的權重和網路定義傳遞至 TensorRT 建構器,以建立 TensorRT 引擎。
  2. 使用此引擎啟動 TensorRT 執行階段。
  3. 將段落和問題饋送至 TensorRT 執行階段,並接收網路預測的答案做為輸出。

圖 2 所示為整體工作流程。

Workflow diagram on how to perform inference with TensorRT runtime engine for BERT QA task. A passage and question are fed to the preprocessing module, which is connected to the TensorRT Engine Execution that runs inference on the loaded TensorRT BERT engine. The output is post-processed obtaining the resulting text answer.
2:使用適用於 BERT QA 任務之 TensorRT 執行階段引擎執行推論的工作流程

執行範例! 

依據下述步驟設定環境,以執行 BERT 推論:

  1. 透過先決條件建立 Docker 映像。
  2. 從經過微調的權重建構 TensorRT 引擎。
  3. 根據段落和查詢執行推論。

我們是使用指令碼執行這些步驟,您可以在 TensorRT BERT 範例儲存庫中找到指令碼。我們有多個可以傳遞至各個指令碼的選項,您可以使用下方示範程式碼快速開始執行:

# Clone the TensorRT repository and navigate to BERT demo directory
 git clone --recursive https://github.com/NVIDIA/TensorRT && cd TensorRT
  
 # Create and launch the Docker image 
 # Here we assume the following: 
 #  - the os being ubuntu-18.04 (see below for other supported versions)
 #  - cuda version is 11.3.1
 bash docker/build.sh --file docker/ubuntu-18.04.Dockerfile --tag tensorrt-ubuntu18.04-cuda11.3 --cuda 11.3.1
  
 # Run the Docker container just created
 bash docker/launch.sh --tag tensorrt-ubuntu18.04-cuda11.3 --gpus all
  
 # cd into the BERT demo folder
 cd $TRT_OSSPATH/demo/BERT
  
 # Download the BERT model fine-tuned checkpoint
 bash scripts/download_model.sh
  
 # Build the TensorRT runtime engine.
 # To build an engine, use the builder.py script.
 mkdir -p engines && python3 builder.py -m models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1/model.ckpt -o engines/bert_large_128.engine -b 1 -s 128 --fp16 -c models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1

最後一個命令則是使用混合精度(–fp16)和 BERT Large SQuAD v2 FP16 序列長度 128 檢查點(-c models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1),建構了最大批次大小為 1(-b 1),序列長度為 128(-s 128)的引擎。

現在,提供一個段落及詢問幾個問題,看一看能解譯多少資訊。

python3 inference.py -e engines/bert_large_128.engine -p "TensorRT is a high performance deep learning inference platform that delivers low latency and high throughput for apps such as recommenders, speech and image/video on NVIDIA GPUs. It includes parsers to import models, and plugins to support novel ops and layers before applying optimizations for inference. Today NVIDIA is open-sourcing parsers and plugins in TensorRT so that the deep learning community can customize and extend these components to take advantage of powerful TensorRT optimizations for your apps." -q "What is TensorRT?" -v models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1/vocab.txt

此命令的結果應類似以下內容:

Passage: TensorRT is a high performance deep learning inference platform that delivers low latency and high throughput for apps such as recommenders, speech and image/video on NVIDIA GPUs. It includes parsers to import models, and plugins to support novel ops and layers before applying optimizations for inference. Today NVIDIA is open-sourcing parsers and plugins in TensorRT so that the deep learning community can customize and extend these components to take advantage of powerful TensorRT optimizations for your apps. 
Question: What is TensorRT?
Answer: 'a high performance deep learning inference platform'

在段落相同而問題不同的情況下,應獲得以下結果:

Question: What is included in TensorRT?
Answer: 'parsers to import models, and plugins to support novel ops and layers before applying optimizations for inference'

模型根據提供之段落文字提供了正確的答案。 此範例是使用 FP16 精度,透過 TensorRT 執行推論。將有助於在 NVIDIA GPU 中的 Tensor 核心上,實現最高效能。我們在測試中測量之 TensorRT 的準確度,相當於使用 FP16 精度的框架內推論。

指令碼選項

指令碼的可用選項如下。docker/build.sh 指令碼使用 docker 資料夾中提供的 Dockerfile 建立 docker 映像。它會根據您選擇做為 Dockerfile 的作業系統,安裝所有的必要套件。在本文章中,我們是使用 ubuntu-18.04,但是也提供 ubuntu-16.04 和 ubuntu-20.04 的 dockerfile。

執行以下指令碼:

bash docker/build.sh --file docker/ubuntu-xx.04.Dockerfile --tag tensorrt-tag --cuda cuda_version

在建立與執行環境之後,下載經過微調的 BERT 權重。請注意,無須預先訓練權重,僅需要經過微調的權重即可建立 TensorRT 引擎。除經過微調的權重外,請使用指定注意力頭數、層數、vocab.txt 檔案等參數的相關配置檔,包括在訓練過程中學到的詞彙。這些與從 NGC 下載的已微調模型封裝在一起,請使用 download_model.sh 指令碼進行下載。您可以針對想要下載的 BERT 模型,指定已微調權重集合,做為此指令碼的一部分。稍後可以將命令列參數控制用於模型建構和推論的確切 BERT 模型:

sh download_model.sh [tf|pyt] [base|large|megatron-large] [128|384] [v2|v1_1] [sparse] [int8-qat]
 tf | pyt tensorflow or pytorch version
 base | large | megatron-large - determine whether to download a BERT-base or BERT-large or megatron model to optimize
 128 | 384 - determine whether to download a BERT model for sequence length 128 or 384
 v2 | v1_1, fine-tuned on squad2 or squad1.1
 sparse, download sparse version
 int8-qat, download int8 weights 

範例:

# Running with default parameters
bash download_model.sh
# Running with custom parameters (BERT-large, FP32 fine-tuned weights, 128 sequence length)
sh download_model.sh large tf fp32 128

此指令碼已預設下載經過微調的 TensorFlow BERT-large,精度為 FP16,序列長度為 128。除已微調模型外,請使用配置檔、列舉模型參數以及將 BERT 模型輸出轉換成文字答案的詞彙檔案。

之後,可以建構 TensorRT 引擎,並運用於 QA 範例,亦即推論。builder.py 指令碼是根據下載的 BERT 已微調模型,建構用於推論的 TensorRT 引擎。

確保提供給以下指令碼的序列長度與下載之模型的序列長度相符。

python3 builder.py [-h] [-m CKPT] [-x ONNX] [-pt PYTORCH] -o OUTPUT
                   [-b BATCH_SIZE] [-s SEQUENCE_LENGTH] -c CONFIG_DIR [-f] [-i]
                   [-t] [-w WORKSPACE_SIZE] [-j SQUAD_JSON] [-v VOCAB_FILE]
                   [-n CALIB_NUM] [-p CALIB_PATH] [-g] [-iln] [-imh] [-sp]
                   [-tcf TIMING_CACHE_FILE] 

以下為選用引數:

   -h, --help    show this help message and exit
   -m CKPT, --ckpt CKPT  The checkpoint file basename, e.g.:
 basename(model.ckpt-766908.data-00000-of-00001) is model.ckpt-766908 (default: None)
   -x ONNX, --onnx ONNX  The ONNX model file path. (default: None)
   -pt PYTORCH, --pytorch PYTORCH
             The PyTorch checkpoint file path. (default: None)
   -o OUTPUT, --output OUTPUT
             The bert engine file, ex bert.engine (default: bert_base_384.engine)
   -b BATCH_SIZE, --batch-size BATCH_SIZE 
 Batch size(s) to optimize for. 
 The engine will be usable with any batch size below this, but may not be optimal for smaller sizes. Can be specified multiple times to optimize for more than one batch size.(default: [])
   -s SEQUENCE_LENGTH, --sequence-length SEQUENCE_LENGTH 
             Sequence length of the BERT model (default: [])
   -c CONFIG_DIR, --config-dir CONFIG_DIR
 The folder containing the bert_config.json, 
 which can be downloaded e.g. from https://github.com/google-research/bert#pre-trained-models (default: None)
   -f, --fp16    Indicates that inference should be run in FP16 precision 
             (default: False)
   -i, --int8    Indicates that inference should be run in INT8 precision 
             (default: False)
   -t, --strict  Indicates that inference should be run in strict precision mode
             (default: False)
   -w WORKSPACE_SIZE, --workspace-size WORKSPACE_SIZE Workspace size in MiB for 
             building the BERT engine (default: 1000)
   -j SQUAD_JSON, --squad-json SQUAD_JSON
 squad json dataset used for int8 calibration (default: squad/dev-v1.1.json)
   -v VOCAB_FILE, --vocab-file VOCAB_FILE 
 Path to file containing entire understandable vocab (default: ./pre-trained_model/uncased_L-24_H-1024_A-16/vocab.txt)
   -n CALIB_NUM, --calib-num CALIB_NUM
             calibration batch numbers (default: 100)
   -p CALIB_PATH, --calib-path CALIB_PATH 
             calibration cache path (default: None)
   -g, --force-fc2-gemm  
             Force use gemm to implement FC2 layer (default: False)
   -iln, --force-int8-skipln 
 Run skip layernorm with INT8 (FP32 or FP16 by default) inputs and output (default: False)
   -imh, --force-int8-multihead
 Run multi-head attention with INT8 (FP32 or FP16 by default) input and output (default: False)
   -sp, --sparse         Indicates that model is sparse (default: False)
   -tcf TIMING_CACHE_FILE, --timing-cache-file TIMING_CACHE_FILE 
 Path to tensorrt build timeing cache file, only available for tensorrt 8.0 and later (default: None) 

範例:

  python3 builder.py -m models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1/model.ckpt -o engines/bert_large_128.engine -b 1 -s 128 --fp16 -c models/fine-tuned/bert_tf_ckpt_large_qa_squad2_amp_128_v19.03.1 

現在應有 TensorRT 引擎 engines/bert_large_128.engine,可用於 QA 的 inference.py指令碼。

本文將於之後說明建構 TensorRT 引擎的流程。您現在可以提供段落和查詢至inference.py,看一看模型是否可以正確地回答查詢。

以下為與推論指令碼互動的幾種方式:

  • 可使用 –passage–question 旗標提供段落和問題,做為命令列引數。
  • 可使用 –passage_file–question_file 旗標,從特定的檔案傳入。
  • 如果在執行過程中未提供這些旗標,則會在執行開始後提示您輸入段落和問題。

以下是 inference.py  腳本的參數:

  Usage: inference.py [-h] [-e ENGINE] [-b BATCH_SIZE]
                     [-p [PASSAGE [PASSAGE ...]]] [-pf PASSAGE_FILE]
                     [-q [QUESTION [QUESTION ...]]] [-qf QUESTION_FILE]
                     [-sq SQUAD_JSON] [-o OUTPUT_PREDICTION_FILE]
                     [-v VOCAB_FILE] [-s SEQUENCE_LENGTH]
                     [--max-query-length MAX_QUERY_LENGTH]
                     [--max-answer-length MAX_ANSWER_LENGTH]
                     [--n-best-size N_BEST_SIZE] [--doc-stride DOC_STRIDE] 

此指令碼是使用預先建構的 TensorRT BERT QA 引擎,根據提供的段落回答問題。

以下為選用引數:

  -h, --help            show this help message and exit
   -e ENGINE, --engine ENGINE
                         Path to BERT TensorRT engine
   -b BATCH_SIZE, --batch-size BATCH_SIZE
                         Batch size for inference.
   -p [PASSAGE [PASSAGE ...]], --passage [PASSAGE [PASSAGE ...]]
                         Text for paragraph/passage for BERT QA
   -pf PASSAGE_FILE, --passage-file PASSAGE_FILE
                         File containing input passage
   -q [QUESTION [QUESTION ...]], --question [QUESTION [QUESTION ...]]
                         Text for query/question for BERT QA
   -qf QUESTION_FILE, --question-file QUESTION_FILE
                         File containing input question
   -sq SQUAD_JSON, --squad-json SQUAD_JSON
                         SQuAD json file
   -o OUTPUT_PREDICTION_FILE, --output-prediction-file OUTPUT_PREDICTION_FILE
                         Output prediction file for SQuAD evaluation
   -v VOCAB_FILE, --vocab-file VOCAB_FILE
                         Path to file containing entire understandable vocab
   -s SEQUENCE_LENGTH, --sequence-length SEQUENCE_LENGTH
                         The sequence length to use. Defaults to 128
   --max-query-length MAX_QUERY_LENGTH
                         The maximum length of a query in number of tokens.
                         Queries longer than this will be truncated
   --max-answer-length MAX_ANSWER_LENGTH
                         The maximum length of an answer that can be generated
   --n-best-size N_BEST_SIZE
                         Total number of n-best predictions to generate in the
                         nbest_predictions.json output file
   --doc-stride DOC_STRIDE
                         When splitting up a long document into chunks, what
                         stride to take between chunks 

使用 TensorRT 進行 BERT 推論 

若需要推論流程的逐步說明和示範,請參閱範例資料夾中的 Python 指令碼 inference.py 和詳細的inference.ipynb Jupyter notebook。以下是一些使用 TensorRT 執行推論的關鍵參數和概念。

BERT,更確切而言是指編碼器層,是使用下列參數管理其運作:

  • 批次大小
  • 序列長度
  • 注意力頭數

這些參數的值是取決於選擇的 BERT 模型,可用於設定 TensorRT 計畫檔案(執行引擎)的配置參數。

針對各個編碼器,同時指定隱藏層數和注意力頭大小。您也可以從 TensorFlow 檢查點檔案中讀取所有較早的參數。

由於已在 SQuAD 資料集上,針對 QA 下游任務微調我們使用的 BERT 模型,因此,網路的輸出(即輸出全連接層)是一段文字,答案會出現於段落中,在範例中稱為 h_output。在產生 TensorRT 引擎之後,即可進行序列化,並在稍後搭配 TensorRT 執行階段使用。

在推論過程中,複製從 CPU 到 GPU 的記憶體,並以非同步之方式執行反向操作,使張量分別進入和退出 GPU 記憶體。 非同步記憶體複製操作是在裝置與主機之間,使運算與記憶體複製操作重疊,以隱藏記憶體傳輸的延遲。圖 3 所示為非同步記憶體複製及核心執行。

Diagram of the TensorRT Runtime execution process. Inputs are asynchronously loaded from host to device. The engine inference is executed asynchronously. The result, again asynchronously, is copied from the device to the host.
3TensorRT 執行階段流程

輸入至 BERT 模型(圖 3)包括:

  • input_ids:張量,具有串連段落的權杖 id 以及做為推論輸入的問題
  • segment_ids:區分段落與問題
  • input_mask:指示序列中的哪些元素是權杖,哪些是填補元素

輸出(start_logitsend_logits)表示網路根據問題在段落內預測答案的跨距。

BERT 推論效能基準測試 

BERT 可以應用於線上和離線使用案例。對話式 AI 等線上 NLP 應用程式,在推論過程中設置了嚴格的延遲預算。必須依序執行多個模型,以回應單一使用者查詢。在做為服務使用時,客戶感受的總時間,包括運算時間以及輸入和輸出網路延遲。時間較長時,將會導致效能緩慢和客戶體驗不佳。

單一模型之確切延遲可能會因為應用程式而異,但是多個即時應用程式需要語言模型是在 10 毫秒內執行。

使用 NVIDIA Ampere 架構 A100 GPU,透過 TensorRT 8 最佳化的 BERT-Large,可在 1.2 毫秒內針對 QA 任務執行推論,類似於 SQuAD 中的任務,批次大小 = 1,序列長度 = 128。

使用 TensorRT 最佳化範例,可以在 10 毫秒延遲預算內,為 BERT-base 或 BERT-large 執行不同的批次大小。例如,在搭載 TensorRT8 的 A30 上,序列長度 = 384,批次大小 = 1 之 BERT-Large 模型的推論延遲為 3.62 毫秒。序列長度 = 384,批次大小 = 1 的相同模型,在純 CPU 平台 (**) 上搭配高度最佳化程式碼為 76 毫秒。

Bar chart of the compute latency in milliseconds for executing BERT-large on an NVIDIA A30 GPU with 3.6ms vs. a CPU-only server with 76ms, the GPU bar is clearly under the 10ms threshold budget for conversational AI applications.

4:在 NVIDIA A30 GPU 與純 CPU 伺服器上執行 BERT-large 的運算延遲以毫秒為單位

效能測量在傳遞張量做為輸入與收集 logits 做為輸出之間,於 QA 任務上執行網路的純運算延遲時間。您可以在儲存庫的指令碼 scripts/inference_benchmark.sh 中,找到針對範例進行基準測試的程式碼。

總結 

NVIDIA 發布的 TensorRT 8.0,使在 A30 GPU 上,於 0.74 毫秒內執行 BERT 推論成為可能。TensorRT 開放原始碼儲存庫中,提供可針對 BERT 推論進行基準測試的程式碼範例。

本文概述了如何使用 TensorRT 範例和效能結果。我們進一步說明了將 BERT 範例做為簡單應用程式和 Jupyter notebook 之一部分的工作流程,您可以在其中傳遞段落及提出相關問題。新的最佳化和可實現的效能使在生產中,將 BERT 運用於對話式 AI 等延遲預算嚴格的應用程式上成為可能。

我們不斷尋求新的想法,以分享新的範例和應用程式。您將 BERT 運用於哪些 NLP 應用程式上?您希望未來能看到哪些範例?

如果對於 TensorRT 範例儲存庫有任何疑問時,請造訪 NVIDIA TensorRT 開發人員論壇,看一看 TensorRT 社群的其他成員是否有解決方法。NVIDIA 註冊開發人員計畫成員也可以在 https://developer.nvidia.com/nvidia-developer-program 上提出錯誤。

NVIDIA 深度學習機構(DLI)提供人工智慧、加速運算和加速資料科學的實作訓練課程,歡迎參加由專業講師的帶領的「建立以 Transformer 為基礎的自然語言處理應用程式」,引導你認識這幾年超夯的自然語言處理(NLP)應用,了解並學會使用以 Transformer 為基礎的模型如 BERT 及 Megatron 等處理文字分類、命名實體識別和問答系統等多項應用。取得 NVIDIA DLI 認證證書,協助自我專業職涯成長。
(*)

  • 純 CPU 規格:Gold 6240@2.60GHz 3.9GHz Turbo (Cascade Lake) HT 關閉,單節點,單插槽,CPU 執行緒數量 = 18,資料=真實,批次大小=1、序列長度=128、nireq=1、精度=FP32、資料=真實、OpenVINO 2019 R2
  • GPU 伺服器規格:Gold 6140@2GHz 3.7GHz Turbo (Skylake) HT 開啟,單節點,雙插槽,CPU 執行緒數量 = 72,T4 16GB,驅動程式版本 418.67 (r418_00),BERT-base,批次大小=1、頭數 = 12、每頭大小 = 64、12 層、序列長度=128、精度=FP16、XLA=有、資料=真實、TensorRT 5.1

(**)

  • 純 CPU 規格:Platinum 8380H@2.90GHz 至 4.3 GHz Turbo (Cooper Lake) HT 關閉,單節點,單插槽,CPU 執行緒數量 = 28,BERT-Large,資料=真實,批次大小=1、序列長度=384、nireq=1、精度=INT8、資料=真實、OpenVINO 2021 R3
  • GPU 伺服器規格:AMD EPYC 7742@2.25GHz 3.4GHz Turbo (Rome) HT 關閉,單節點,CPU 執行緒數量 = 64,A30(GA100) 1*24258 MiB 1*56 SM,驅動程式版本 470.29 (r470_00),BERT-Large,批次大小=1、序列長度=384、精度=INT8、TensorRT 8.0