0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

TensorRT支持使用8位整數(shù)表示量化的浮點(diǎn)值

星星科技指導(dǎo)員 ? 來源:NVIDIA ? 作者:Ken He ? 2022-05-13 16:28 ? 次閱讀

7.1. Introduction to Quantization

TensorRT 支持使用 8 位整數(shù)來表示量化的浮點(diǎn)值。量化方案是對稱均勻量化 – 量化值以有符號 INT8 表示,從量化到非量化值的轉(zhuǎn)換只是一個乘法。在相反的方向上,量化使用倒數(shù)尺度,然后是舍入和鉗位。

要啟用任何量化操作,必須在構(gòu)建器配置中設(shè)置 INT8 標(biāo)志。

7.1.1. Quantization Workflows

創(chuàng)建量化網(wǎng)絡(luò)有兩種工作流程:

訓(xùn)練后量化(PTQ: Post-training quantization) 在網(wǎng)絡(luò)經(jīng)過訓(xùn)練后得出比例因子。 TensorRT 為 PTQ 提供了一個工作流程,稱為校準(zhǔn)(calibration),當(dāng)網(wǎng)絡(luò)在代表性輸入數(shù)據(jù)上執(zhí)行時,它測量每個激活張量內(nèi)的激活分布,然后使用該分布來估計(jì)張量的尺度值。

量化感知訓(xùn)練(QAT: Quantization-aware training) 在訓(xùn)練期間計(jì)算比例因子。這允許訓(xùn)練過程補(bǔ)償量化和去量化操作的影響。

TensorRT 的量化工具包是一個 PyTorch 庫,可幫助生成可由 TensorRT 優(yōu)化的 QAT 模型。您還可以利用工具包的 PTQ 方式在 PyTorch 中執(zhí)行 PTQ 并導(dǎo)出到 ONNX。

7.1.2. Explicit vs Implicit Quantization

量化網(wǎng)絡(luò)可以用兩種方式表示:

在隱式量化網(wǎng)絡(luò)中,每個量化張量都有一個相關(guān)的尺度。在讀寫張量時,尺度用于隱式量化和反量化值。

在處理隱式量化網(wǎng)絡(luò)時,TensorRT 在應(yīng)用圖形優(yōu)化時將模型視為浮點(diǎn)模型,并適時的使用 INT8 來優(yōu)化層執(zhí)行時間。如果一個層在 INT8 中運(yùn)行得更快,那么它在 INT8 中執(zhí)行。否則,使用 FP32 或 FP16。在這種模式下,TensorRT 僅針對性能進(jìn)行優(yōu)化,您幾乎無法控制 INT8 的使用位置——即使您在 API 級別明確設(shè)置層的精度,TensorRT 也可能在圖優(yōu)化期間將該層與另一個層融合,并丟失它必須在 INT8 中執(zhí)行的信息。 TensorRT 的 PTQ 功能可生成隱式量化網(wǎng)絡(luò)。

在顯式量化的網(wǎng)絡(luò)中,在量化和未量化值之間轉(zhuǎn)換的縮放操作由圖中的IQuantizeLayer ( C++ , Python)和IDequantizeLayer ( C++ , Python ) 節(jié)點(diǎn)顯式表示 – 這些節(jié)點(diǎn)此后將被稱為 Q/DQ 節(jié)點(diǎn)。與隱式量化相比,顯式形式精確地指定了與 INT8 之間的轉(zhuǎn)換在何處執(zhí)行,并且優(yōu)化器將僅執(zhí)行由模型語義規(guī)定的精度轉(zhuǎn)換,即使:

  • 添加額外的轉(zhuǎn)換可以提高層精度(例如,選擇 FP16 內(nèi)核實(shí)現(xiàn)而不是 INT8 實(shí)現(xiàn))
  • 添加額外的轉(zhuǎn)換會導(dǎo)致引擎執(zhí)行得更快(例如,選擇 INT8 內(nèi)核實(shí)現(xiàn)來執(zhí)行指定為具有浮點(diǎn)精度的層,反之亦然)

ONNX 使用顯式量化表示 – 當(dāng) PyTorch 或 TensorFlow 中的模型導(dǎo)出到 ONNX 時,框架圖中的每個偽量化操作都導(dǎo)出為 Q,然后是 DQ。由于 TensorRT 保留了這些層的語義,因此您可以期望任務(wù)準(zhǔn)確度非常接近框架中看到的準(zhǔn)確度。雖然優(yōu)化保留了量化和去量化的位置,但它們可能會改變模型中浮點(diǎn)運(yùn)算的順序,因此結(jié)果不會按位相同。 請注意,與 TensorRT 的 PTQ 相比,在框架中執(zhí)行 QAT 或 PTQ 然后導(dǎo)出到 ONNX 將產(chǎn)生一個明確量化的模型。Table 2. Implicit vs Explicit Quantization

有關(guān)量化的更多背景信息,請參閱深度學(xué)習(xí)推理的整數(shù)量化:原理和實(shí)證評估論文。

7.1.3. Per-Tensor and Per-Channel Quantization

有兩種常見的量化尺度粒度:

每張量量化:其中使用單個比例值(標(biāo)量)來縮放整個張量。

每通道量化:沿給定軸廣播尺度張量 – 對于卷積神經(jīng)網(wǎng)絡(luò),這通常是通道軸。

通過顯式量化,權(quán)重可以使用每張量量化進(jìn)行量化,也可以使用每通道量化進(jìn)行量化。在任何一種情況下,比例精度都是 FP32。激活只能使用每張量量化來量化。

當(dāng)使用每通道量化時,量化軸必須是輸出通道軸。例如,當(dāng)使用KCRS表示法描述 2D 卷積的權(quán)重時, K是輸出通道軸,權(quán)重量化可以描述為:

For each k in K:
    For each c in C:
        For each r in R:
            For each s in S:
                output[k,c,r,s] := clamp(round(input[k,c,r,s] / scale[k]))

比例尺是一個系數(shù)向量,必須與量化軸具有相同的大小。量化尺度必須由所有正浮點(diǎn)系數(shù)組成。四舍五入方法是四舍五入到最近的關(guān)系到偶數(shù),并且鉗位在[-128, 127]范圍內(nèi)。

除了定義為的逐點(diǎn)操作外,反量化的執(zhí)行方式類似:

output[k,c,r,s] := input[k,c,r,s] * scale[k]

TensorRT 僅支持激活張量的每張量量化,但支持卷積、反卷積、全連接層和 MatMul 的每通道權(quán)重量化,其中第二個輸入是常數(shù)且兩個輸入矩陣都是二維的。7.2. Setting Dynamic Range

TensorRT 提供 API 來直接設(shè)置動態(tài)范圍(必須由量化張量表示的范圍),以支持在 TensorRT 之外計(jì)算這些值的隱式量化。 API 允許使用最小值和最大值設(shè)置張量的動態(tài)范圍。由于 TensorRT 目前僅支持對稱范圍,因此使用max(abs(min_float), abs(max_float))計(jì)算比例。請注意,當(dāng)abs(min_float) != abs(max_float)時,TensorRT 使用比配置更大的動態(tài)范圍,這可能會增加舍入誤差。

將在 INT8 中執(zhí)行的操作的所有浮點(diǎn)輸入和輸出都需要動態(tài)范圍。

您可以按如下方式設(shè)置張量的動態(tài)范圍: C++

tensor-》setDynamicRange(min_float, max_float);

Python

tensor.dynamic_range = (min_float, max_float)

sampleINT8API說明了這些 API 在 C++ 中的使用。

7.3. Post-Training Quantization using Calibration

在訓(xùn)練后量化中,TensorRT 計(jì)算網(wǎng)絡(luò)中每個張量的比例值。這個過程稱為校準(zhǔn),需要您提供有代表性的輸入數(shù)據(jù),TensorRT 在其上運(yùn)行網(wǎng)絡(luò)以收集每個激活張量的統(tǒng)計(jì)信息。

所需的輸入數(shù)據(jù)量取決于應(yīng)用程序,但實(shí)驗(yàn)表明大約 500 張圖像足以校準(zhǔn) ImageNet 分類網(wǎng)絡(luò)。

給定激活張量的統(tǒng)計(jì)數(shù)據(jù),決定最佳尺度值并不是一門精確的科學(xué)——它需要平衡量化表示中的兩個誤差源:離散化誤差(隨著每個量化值表示的范圍變大而增加)和截?cái)嗾`差(其中值被限制在可表示范圍的極限)。因此,TensorRT 提供了多個不同的校準(zhǔn)器,它們以不同的方式計(jì)算比例。較舊的校準(zhǔn)器還為 GPU 執(zhí)行層融合,以在執(zhí)行校準(zhǔn)之前優(yōu)化掉不需要的張量。這在使用 DLA 時可能會出現(xiàn)問題,其中融合模式可能不同,并且可以使用kCALIBRATE_BEFORE_FUSION量化標(biāo)志覆蓋。

IInt8EntropyCalibrator2

熵校準(zhǔn)選擇張量的比例因子來優(yōu)化量化張量的信息論內(nèi)容,通常會抑制分布中的異常值。這是當(dāng)前推薦的熵校準(zhǔn)器,是 DLA 所必需的。默認(rèn)情況下,校準(zhǔn)發(fā)生在圖層融合之前。推薦用于基于 CNN 的網(wǎng)絡(luò)。

IInt8MinMaxCalibrator

該校準(zhǔn)器使用激活分布的整個范圍來確定比例因子。它似乎更適合 NLP 任務(wù)。默認(rèn)情況下,校準(zhǔn)發(fā)生在圖層融合之前。推薦用于 NVIDIA BERT(谷歌官方實(shí)現(xiàn)的優(yōu)化版本)等網(wǎng)絡(luò)。

IInt8EntropyCalibrator

這是原始的熵校準(zhǔn)器。它的使用沒有 LegacyCalibrator 復(fù)雜,通常會產(chǎn)生更好的結(jié)果。默認(rèn)情況下,校準(zhǔn)發(fā)生在圖層融合之后。

IInt8LegacyCalibrator

該校準(zhǔn)器與 TensorRT 2.0 EA 兼容。此校準(zhǔn)器需要用戶參數(shù)化,并且在其他校準(zhǔn)器產(chǎn)生不良結(jié)果時作為備用選項(xiàng)提供。默認(rèn)情況下,校準(zhǔn)發(fā)生在圖層融合之后。您可以自定義此校準(zhǔn)器以實(shí)現(xiàn)最大百分比,例如,觀察到 99.99% 的最大百分比對于 NVIDIA BERT 具有最佳精度。

構(gòu)建 INT8 引擎時,構(gòu)建器執(zhí)行以下步驟:

構(gòu)建一個 32 位引擎,在校準(zhǔn)集上運(yùn)行它,并為激活值分布的每個張量記錄一個直方圖。

從直方圖構(gòu)建一個校準(zhǔn)表,為每個張量提供一個比例值。

根據(jù)校準(zhǔn)表和網(wǎng)絡(luò)定義構(gòu)建 INT8 引擎。

校準(zhǔn)可能很慢;因此步驟 2 的輸出(校準(zhǔn)表)可以被緩存和重用。這在多次構(gòu)建相同的網(wǎng)絡(luò)時非常有用,例如,在多個平臺上 – 特別是,它可以簡化工作流程,在具有離散 GPU 的機(jī)器上構(gòu)建校準(zhǔn)表,然后在嵌入式平臺上重用它??稍诖颂幷业綐颖拘?zhǔn)表。 在運(yùn)行校準(zhǔn)之前,TensorRT 會查詢校準(zhǔn)器實(shí)現(xiàn)以查看它是否有權(quán)訪問緩存表。如果是這樣,它直接進(jìn)行到上面的步驟 3。緩存數(shù)據(jù)作為指針和長度傳遞。

只要校準(zhǔn)發(fā)生在層融合之前,校準(zhǔn)緩存數(shù)據(jù)就可以在平臺之間以及為不同設(shè)備構(gòu)建引擎時移植。這意味著在默認(rèn)情況下使用IInt8EntropyCalibrator2或IInt8MinMaxCalibrator校準(zhǔn)器或設(shè)置QuantizationFlag::kCALIBRATE_BEFORE_FUSION時,校準(zhǔn)緩存是可移植的。不能保證跨平臺或設(shè)備的融合是相同的,因此在層融合之后進(jìn)行校準(zhǔn)可能不會產(chǎn)生便攜式校準(zhǔn)緩存。 除了量化激活,TensorRT 還必須量化權(quán)重。它使用對稱量化和使用權(quán)重張量中找到的最大絕對值計(jì)算的量化比例。對于卷積、反卷積和全連接權(quán)重,尺度是每個通道的。

注意:當(dāng)構(gòu)建器配置為使用 INT8 I/O 時,TensorRT 仍希望校準(zhǔn)數(shù)據(jù)位于 FP32 中。您可以通過將 INT8 I/O 校準(zhǔn)數(shù)據(jù)轉(zhuǎn)換為 FP32 精度來創(chuàng)建 FP32 校準(zhǔn)數(shù)據(jù)。您還必須確保 FP32 投射校準(zhǔn)數(shù)據(jù)在[-128.0F, 127.0F]范圍內(nèi),因此可以轉(zhuǎn)換為 INT8 數(shù)據(jù)而不會造成任何精度損失。

INT8 校準(zhǔn)可與動態(tài)范圍 API 一起使用。手動設(shè)置動態(tài)范圍會覆蓋 INT8 校準(zhǔn)生成的動態(tài)范圍。

注意:校準(zhǔn)是確定性的——也就是說,如果您在同一設(shè)備上以相同的順序?yàn)?TensorRT 提供相同的校準(zhǔn)輸入,則生成的比例在不同的運(yùn)行中將是相同的。當(dāng)提供相同的校準(zhǔn)輸入時,當(dāng)使用具有相同批量大小的相同設(shè)備生成時,校準(zhǔn)緩存中的數(shù)據(jù)將按位相同。當(dāng)使用不同的設(shè)備、不同的批量大小或使用不同的校準(zhǔn)輸入生成校準(zhǔn)緩存時,不能保證校準(zhǔn)緩存中的確切數(shù)據(jù)按位相同。

7.3.1. INT8 Calibration Using C++

要向 TensorRT 提供校準(zhǔn)數(shù)據(jù),請實(shí)現(xiàn)IInt8Calibrator接口

關(guān)于這個任務(wù)

構(gòu)建器調(diào)用校準(zhǔn)器如下:

首先,它查詢接口的批次大小并調(diào)用getBatchSize()來確定預(yù)期的輸入批次的大小。

然后,它反復(fù)調(diào)用getBatch()來獲取批量輸入。批次必須與getBatchSize()的批次大小完全相同。當(dāng)沒有更多批次時, getBatch()必須返回false 。

實(shí)現(xiàn)校準(zhǔn)器后,您可以配置構(gòu)建器以使用它:

config->setInt8Calibrator(calibrator.get());

要緩存校準(zhǔn)表,請實(shí)現(xiàn)writeCalibrationCache()和readCalibrationCache()方法。

有關(guān)配置 INT8 校準(zhǔn)器對象的更多信息,請參閱sampleINT8

7.3.2. Calibration Using Python

以下步驟說明了如何使用 Python API 創(chuàng)建 INT8 校準(zhǔn)器對象。 程序

導(dǎo)入 TensorRT:

import tensorrt as trt
2.與測試/驗(yàn)證數(shù)據(jù)集類似,使用一組輸入文件作為校準(zhǔn)數(shù)據(jù)集。確保校準(zhǔn)文件代表整個推理數(shù)據(jù)文件。為了讓 TensorRT 使用校準(zhǔn)文件,您必須創(chuàng)建一個批處理流對象。批處理流對象用于配置校準(zhǔn)器。
NUM_IMAGES_PER_BATCH = 5
batchstream = ImageBatchStream(NUM_IMAGES_PER_BATCH, calibration_files)
3.使用輸入節(jié)點(diǎn)名稱和批處理流創(chuàng)建一個Int8_calibrator對象:
Int8_calibrator = EntropyCalibrator(["input_node_name"], batchstream)
4.設(shè)置 INT8 模式和 INT8 校準(zhǔn)器:
config.set_flag(trt.BuilderFlag.INT8)
config.int8_calibrator = Int8_calibrator

7.4. Explicit Quantization

當(dāng) TensorRT 檢測到網(wǎng)絡(luò)中存在 Q/DQ 層時,它會使用顯式精度處理邏輯構(gòu)建一個引擎。

AQ/DQ 網(wǎng)絡(luò)必須在啟用 INT8 精度構(gòu)建器標(biāo)志的情況下構(gòu)建:

config->setFlag(BuilderFlag::kINT8);

在顯式量化中,表示與 INT8 之間的網(wǎng)絡(luò)變化是顯式的,因此,INT8 不能用作類型約束。7.4.1. Quantized Weights

Q/DQ 模型的權(quán)重必須使用 FP32 數(shù)據(jù)類型指定。 TensorRT 使用對權(quán)重進(jìn)行操作的IQuantizeLayer的比例對權(quán)重進(jìn)行量化。量化的權(quán)重存儲在引擎文件中。也可以使用預(yù)量化權(quán)重,但必須使用 FP32 數(shù)據(jù)類型指定。 Q 節(jié)點(diǎn)的 scale 必須設(shè)置為1.0F ,但 DQ 節(jié)點(diǎn)必須是真實(shí)的 scale 值。

7.4.2. ONNX Support

當(dāng)使用 Quantization Aware Training (QAT) 在 PyTorch 或 TensorFlow 中訓(xùn)練的模型導(dǎo)出到 ONNX 時,框架圖中的每個偽量化操作都會導(dǎo)出為一對QuantizeLinear和DequantizeLinear ONNX 運(yùn)算符。

當(dāng) TensorRT 導(dǎo)入 ONNX 模型時,ONNX QuantizeLinear算子作為IQuantizeLayer實(shí)例導(dǎo)入,ONNX DequantizeLinear算子作為IDequantizeLayer實(shí)例導(dǎo)入。

使用 opset 10 的 ONNX 引入了對 QuantizeLinear/DequantizeLinear 的支持,并且在 opset 13 中添加了量化軸屬性(每通道量化所必需的)。 PyTorch 1.8 引入了對使用 opset 13 將 PyTorch 模型導(dǎo)出到 ONNX 的支持。

警告: ONNX GEMM 算子是一個可以按通道量化的示例。 PyTorch torch.nn.Linear層導(dǎo)出為 ONNX GEMM 算子,具有(K, C)權(quán)重布局并啟用了transB GEMM 屬性(這會在執(zhí)行 GEMM 操作之前轉(zhuǎn)置權(quán)重)。另一方面,TensorFlow在 ONNX 導(dǎo)出之前預(yù)轉(zhuǎn)置權(quán)重(C, K) :

PyTorch: $y = xW^T$

TensorFlow: $y = xW$

因此,PyTorch 權(quán)重由 TensorRT 轉(zhuǎn)置。權(quán)重在轉(zhuǎn)置之前由 TensorRT 進(jìn)行量化,因此源自從 PyTorch 導(dǎo)出的 ONNX QAT 模型的 GEMM 層使用維度0進(jìn)行每通道量化(軸K = 0 );而源自 TensorFlow 的模型使用維度1 (軸K = 1 )。

TensorRT 不支持使用 INT8 張量或量化運(yùn)算符的預(yù)量化 ONNX 模型。具體來說,以下 ONNX 量化運(yùn)算符不受支持,如果在 TensorRT 導(dǎo)入 ONNX 模型時遇到它們,則會生成導(dǎo)入錯誤:

QLinearConv/QLinearMatmul

ConvInteger/MatmulInteger

7.4.3. TensorRT Processing Of Q/DQ Networks

當(dāng) TensorRT 在 Q/DQ 模式下優(yōu)化網(wǎng)絡(luò)時,優(yōu)化過程僅限于不改變網(wǎng)絡(luò)算術(shù)正確性的優(yōu)化。由于浮點(diǎn)運(yùn)算的順序會產(chǎn)生不同的結(jié)果(例如,重寫 $a * s + b * s$ 為 $(a + b) * s$是一個有效的優(yōu)化)。允許這些差異通常是后端優(yōu)化的基礎(chǔ),這也適用于將具有 Q/DQ 層的圖轉(zhuǎn)換為使用 INT8 計(jì)算。

Q/DQ 層控制網(wǎng)絡(luò)的計(jì)算和數(shù)據(jù)精度。 IQuantizeLayer實(shí)例通過量化將 FP32 張量轉(zhuǎn)換為 INT8 張量, IDequantizeLayer實(shí)例通過反量化將INT8張量轉(zhuǎn)換為 FP32 張量。 TensorRT 期望量化層的每個輸入上都有一個 Q/DQ 層對。量化層是深度學(xué)習(xí)層,可以通過與IQuantizeLayer和IDequantizeLayer實(shí)例融合來轉(zhuǎn)換為量化層。當(dāng) TensorRT 執(zhí)行這些融合時,它會將可量化層替換為實(shí)際使用 INT8 計(jì)算操作對 INT8 數(shù)據(jù)進(jìn)行操作的量化層。

對于本章中使用的圖表,綠色表示 INT8 精度,藍(lán)色表示浮點(diǎn)精度。箭頭代表網(wǎng)絡(luò)激活張量,正方形代表網(wǎng)絡(luò)層。

下圖。 可量化的AveragePool層(藍(lán)色)與 DQ 層和 Q 層融合。所有三層都被量化的AveragePool層(綠色)替換。

在網(wǎng)絡(luò)優(yōu)化期間,TensorRT 在稱為 Q/DQ 傳播的過程中移動 Q/DQ 層。傳播的目標(biāo)是最大化以低精度處理的圖的比例。因此,TensorRT 向后傳播 Q 節(jié)點(diǎn)(以便盡可能早地進(jìn)行量化)和向前傳播 DQ 節(jié)點(diǎn)(以便盡可能晚地進(jìn)行去量化)。 Q-layers 可以與 commute-with-Quantization 層交換位置,DQ-layers 可以與 commute-with-Dequantization 層交換位置。

A layer Op commutes with quantization if $Q (Op (x) ) ==Op (Q (x) )$

Similarly, a layer Op commutes with dequantization if $Op (DQ (x) ) ==DQ (Op (x) )$

下圖說明了 DQ 前向傳播和 Q 后向傳播。這些是對模型的合法重寫,因?yàn)?Max Pooling 具有 INT8 實(shí)現(xiàn),并且因?yàn)?Max Pooling 與 DQ 和 Q 通訊。

下圖描述 DQ 前向傳播和 Q 后向傳播的插圖。

注意:

為了理解最大池化交換,讓我們看一下應(yīng)用于某個任意輸入的最大池化操作的輸出。 Max Pooling應(yīng)用于輸入系數(shù)組并輸出具有最大值的系數(shù)。對于由系數(shù)組成的組i : ${x_0 。 . x_m}$

$utput_i := max({x_0, x_1, … x_m}) = max({max({max({x_0, x_1}), x_2)}, … x_m})$

因此,在不失一般性(WLOG)的情況下查看兩個任意系數(shù)就足夠了:

$x_j = max({x_j, x_k})\ \ \ for\ \ \ x_j 》= x_k$

對于量化函數(shù)$Q(a, scale, x_max, x_min) := truncate(round(a/scale), x_max,x_min)$ 來說$scale》0$, 注意(不提供證明,并使用簡化符號):

$Q(x_j, scale) 》= Q(x_k, scale)\ \ \ for\ \ \ x_j 》= x_k$

因此:

$max({Q(x_j, scale), Q(x_k, scale)}) = Q(x_j, scale)\ \ \ for\ \ \ x_j 》= x_k$

然而,根據(jù)定義:

$Q(max({x_j, x_k}), scale) = Q(x_j, scale)\ \ \ for\ \ \ x_j 》= x_k$

函數(shù) $max$ commutes-with-quantization 和 Max Pooling 也是如此。

類似地,對于去量化,函數(shù)$DQ (a, scale) :=a * scale with scale》0$ 我們可以證明:

$max({DQ(x_j, scale), DQ(x_k, scale)}) = DQ(x_j, scale) = DQ(max({x_j, x_k}), scale)\ \ \ for\ \ \ x_j 》= x_k$

量化層和交換層的處理方式是有區(qū)別的。兩種類型的層都可以在 INT8 中計(jì)算,但可量化層也與 DQ 輸入層和 Q 輸出層融合。例如, AveragePooling層(可量化)不與 Q 或 DQ 交換,因此使用 Q/DQ 融合對其進(jìn)行量化,如第一張圖所示。這與如何量化 Max Pooling(交換)形成對比。

7.4.4. Q/DQ Layer-Placement Recommendations

Q/DQ 層在網(wǎng)絡(luò)中的放置會影響性能和準(zhǔn)確性。由于量化引入的誤差,激進(jìn)量化會導(dǎo)致模型精度下降。但量化也可以減少延遲。此處列出了在網(wǎng)絡(luò)中放置 Q/DQ 層的一些建議。

量化加權(quán)運(yùn)算(卷積、轉(zhuǎn)置卷積和 GEMM)的所有輸入。權(quán)重和激活的量化降低了帶寬需求,還使 INT8 計(jì)算能夠加速帶寬受限和計(jì)算受限的層。

下圖 TensorRT 如何融合卷積層的兩個示例。在左邊,只有輸入被量化。在右邊,輸入和輸出都被量化了。

默認(rèn)情況下,不量化加權(quán)運(yùn)算的輸出。保留更高精度的去量化輸出有時很有用。例如,如果線性運(yùn)算后面跟著一個激活函數(shù)(SiLU,下圖中),它需要更高的精度輸入才能產(chǎn)生可接受的精度。

不要在訓(xùn)練框架中模擬批量歸一化和 ReLU 融合,因?yàn)?TensorRT 優(yōu)化保證保留這些操作的算術(shù)語義。

TensorRT 可以在加權(quán)層之后融合element-wise addition,這對于像 ResNet 和 EfficientNet 這樣具有跳躍連接的模型很有用。element-wise addition層的第一個輸入的精度決定了融合輸出的精度。

比如下圖中,$x_f^1$的精度是浮點(diǎn)數(shù),所以融合卷積的輸出僅限于浮點(diǎn)數(shù),后面的Q層不能和卷積融合。

相比之下,當(dāng)$x_f^1$量化為 INT8 時,如下圖所示,融合卷積的輸出也是 INT8,尾部的 Q 層與卷積融合。

為了獲得額外的性能,請嘗試使用 Q/DQ 量化不交換的層。目前,具有 INT8 輸入的非加權(quán)層也需要 INT8 輸出,因此對輸入和輸出都進(jìn)行量化。

如果 TensorRT 無法將操作與周圍的 Q/DQ 層融合,則性能可能會降低,因此在添加 Q/DQ 節(jié)點(diǎn)時要保守,并牢記準(zhǔn)確性和 TensorRT 性能進(jìn)行試驗(yàn)。

下圖是額外 Q/DQ 操作可能導(dǎo)致的次優(yōu)融合示例(突出顯示的淺綠色背景矩形)。

對激活使用逐張量量化;和每個通道的權(quán)重量化。這種配置已經(jīng)被經(jīng)驗(yàn)證明可以帶來最佳的量化精度。

您可以通過啟用 FP16 進(jìn)一步優(yōu)化引擎延遲。 TensorRT 盡可能嘗試使用 FP16 而不是 FP32(目前并非所有層類型都支持)

7.4.5. Q/DQ Limitations

TensorRT 執(zhí)行的一些 Q/DQ 圖重寫優(yōu)化比較兩個或多個 Q/DQ 層之間的量化尺度值,并且僅在比較的量化尺度相等時才執(zhí)行圖重寫。改裝可改裝的 TensorRT 引擎時,可以為 Q/DQ 節(jié)點(diǎn)的尺度分配新值。在 Q/DQ 引擎的改裝操作期間,TensorRT 檢查是否為參與尺度相關(guān)優(yōu)化的 Q/DQ 層分配了破壞重寫優(yōu)化的新值,如果為真則拋出異常。

下比較 Q1 和 Q2 的尺度是否相等的示例,如果相等,則允許它們向后傳播。如果使用 Q1 和 Q2 的新值對引擎進(jìn)行改裝,使得Q1 != Q2 ,則異常中止改裝過程。

7.4.6. QAT Networks Using TensorFlow

目前,沒有用于 TensorRT 的 TensorFlow 量化工具包,但是,有幾種推薦的方法:

TensorFlow 2 引入了一個新的 API 來在 QAT(量化感知訓(xùn)練)中執(zhí)行偽量化: tf.quantization.quantize_and_dequantize_v2 該算子使用與 TensorRT 的量化方案一致的對稱量化。我們推薦這個 API 而不是 TensorFlow 1 tf.quantization.quantize_and_dequantize API。 導(dǎo)出到 ONNX 時,可以使用tf2onnx轉(zhuǎn)換器將quantize_and_dequantize_v2算子轉(zhuǎn)換為一對 QuantizeLinear 和 DequantizeLinear 算子(Q/DQ 算子) 。請參閱quantization_ops_rewriter以了解如何執(zhí)行此轉(zhuǎn)換。

默認(rèn)情況下,TensorFlow 將tf.quantization.quantize_and_dequantize_v2算子(導(dǎo)出到 ONNX 后的 Q/DQ 節(jié)點(diǎn))放在算子輸出上,而 TensorRT 建議將 Q/DQ 放在層輸入上。有關(guān)詳細(xì)信息,請參閱QDQ 位置。

TensorFlow 1 不支持每通道量化 (PCQ)。建議將 PCQ 用于權(quán)重,以保持模型的準(zhǔn)確性。

7.4.7. QAT Networks Using PyTorch

PyTorch 1.8.0 和前版支持 ONNX QuantizeLinear / DequantizeLinear ,支持每通道縮放。您可以使用pytorch-quantization進(jìn)行 INT8 校準(zhǔn),運(yùn)行量化感知微調(diào),生成 ONNX,最后使用 TensorRT 在此 ONNX 模型上運(yùn)行推理。更多詳細(xì)信息可以在PyTorch-Quantization Toolkit 用戶指南中找到。

7.5. INT8 Rounding Modes

關(guān)于作者

Ken He 是 NVIDIA 企業(yè)級開發(fā)者社區(qū)經(jīng)理 & 高級講師,擁有多年的 GPU 和人工智能開發(fā)經(jīng)驗(yàn)。自 2017 年加入 NVIDIA 開發(fā)者社區(qū)以來,完成過上百場培訓(xùn),幫助上萬個開發(fā)者了解人工智能和 GPU 編程開發(fā)。在計(jì)算機(jī)視覺,高性能計(jì)算領(lǐng)域完成過多個獨(dú)立項(xiàng)目。并且,在機(jī)器人無人機(jī)領(lǐng)域,有過豐富的研發(fā)經(jīng)驗(yàn)。對于圖像識別,目標(biāo)的檢測與跟蹤完成過多種解決方案。曾經(jīng)參與 GPU 版氣象模式GRAPES,是其主要研發(fā)者。

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1461

    瀏覽量

    61492
  • 引擎
    +關(guān)注

    關(guān)注

    1

    文章

    353

    瀏覽量

    22453
收藏 人收藏

    評論

    相關(guān)推薦

    鴻蒙原生應(yīng)用元服務(wù)開發(fā)-倉頡基礎(chǔ)數(shù)據(jù)類型整數(shù)類型

    ,如果它的超出了上下文要求的整數(shù)類型的表示范圍,編譯器將會報錯。 let x: Int8 = 128 // Error, 128 out of the range of Int
    發(fā)表于 09-13 14:55

    鴻蒙原生應(yīng)用元服務(wù)開發(fā)-倉頡基礎(chǔ)數(shù)據(jù)類型浮點(diǎn)類型

    數(shù)的性質(zhì)和范圍。在多種浮點(diǎn)類型都適合的情況下,首選精度高的浮點(diǎn)類型,因?yàn)榫鹊偷?b class='flag-5'>浮點(diǎn)類型的累計(jì)計(jì)算誤差很容易擴(kuò)散,并且它能精確表示整數(shù)范圍
    發(fā)表于 09-10 10:22

    labview數(shù)據(jù)類型的取值范圍是多少

    ) :取值范圍是-128到127。這是因?yàn)樗褂昧?b class='flag-5'>8二進(jìn)制數(shù)表示,其中一用于表示符號(正負(fù))。 I16(16
    的頭像 發(fā)表于 09-04 17:33 ?270次閱讀

    深度神經(jīng)網(wǎng)絡(luò)模型量化的基本方法

    深度神經(jīng)網(wǎng)絡(luò)模型量化是深度學(xué)習(xí)領(lǐng)域中的一種重要優(yōu)化技術(shù),旨在通過減少模型參數(shù)的精度(即從高精度浮點(diǎn)數(shù)如32浮點(diǎn)數(shù)FP32降低到低精度整數(shù)
    的頭像 發(fā)表于 07-15 11:26 ?454次閱讀

    未來輕量級深度學(xué)習(xí)技術(shù)探索

    除了輕量級架構(gòu)設(shè)計(jì)外,作者提到了可以應(yīng)用于壓縮給定架構(gòu)的各種高效算法。例如,量化方法 旨在減少數(shù)據(jù)所需的存儲空間,通常是通過用8或16數(shù)字代替32
    發(fā)表于 04-23 15:54 ?294次閱讀
    未來輕量級深度學(xué)習(xí)技術(shù)探索

    verilog語音實(shí)現(xiàn)浮點(diǎn)運(yùn)算

    Verilog可以通過使用IEEE標(biāo)準(zhǔn)的浮點(diǎn)數(shù)表示來實(shí)現(xiàn)浮點(diǎn)運(yùn)算。下面是一個基本的Verilog模塊示例,展示了如何進(jìn)行加法、乘法和除法等常見的浮點(diǎn)運(yùn)算操作: module
    發(fā)表于 03-25 21:49

    分享一個適用于 HPM6300 AndeStar V5 DSP 擴(kuò)展指令的 32有符號整數(shù) 全周傅里葉算法加速器

    浮點(diǎn)類型參數(shù),spec上看實(shí)際DSP擴(kuò)展并沒有實(shí)際硬浮點(diǎn)能力,估計(jì)是轉(zhuǎn)換成整型進(jìn)行計(jì)算的。那么來回轉(zhuǎn)換的開銷消弱了加速的意義。 適用于數(shù)字化電力系統(tǒng),IEC61850 9-2 使用 32 有符號
    發(fā)表于 03-21 13:12

    一文帶你秒懂IEEE 754浮點(diǎn)數(shù)

    一、簡介1、常見的浮點(diǎn)數(shù)表示方式是IEEE754標(biāo)準(zhǔn),它規(guī)定了浮點(diǎn)數(shù)的存儲格式和運(yùn)算規(guī)則,這個標(biāo)準(zhǔn)定義了兩種浮點(diǎn)數(shù)表示:單精度和雙精度。2、任何一個浮點(diǎn)數(shù)的二進(jìn)制數(shù)可以寫為:NUM=(
    的頭像 發(fā)表于 03-18 08:09 ?6300次閱讀
    一文帶你秒懂IEEE 754<b class='flag-5'>浮點(diǎn)</b>數(shù)

    modbus浮點(diǎn)數(shù)怎么讀取

    Modbus是一種通信協(xié)議,常用于工業(yè)自動化系統(tǒng)中的設(shè)備之間的通信。它支持多種數(shù)據(jù)類型,包括整數(shù)、浮點(diǎn)數(shù)、字符串等。浮點(diǎn)數(shù)在工業(yè)領(lǐng)域中廣泛應(yīng)用,因此了解如何讀取和處理Modbus
    的頭像 發(fā)表于 12-28 14:38 ?4743次閱讀

    單精度和雙精度浮點(diǎn)數(shù)的區(qū)別

    。 單精度浮點(diǎn)數(shù),也稱為單精度浮點(diǎn)數(shù)格式,用于在計(jì)算機(jī)中表示32二進(jìn)制格式的浮點(diǎn)數(shù)。一個單精度浮點(diǎn)
    的頭像 發(fā)表于 12-15 10:25 ?4189次閱讀

    javascript的typeof返回哪些數(shù)據(jù)類型?

    ":布爾類型,表示一個是true還是false。 "number":數(shù)值類型,包括整數(shù)浮點(diǎn)數(shù)。JavaScript中的所有數(shù)字都是以64
    的頭像 發(fā)表于 12-03 11:41 ?700次閱讀

    超出int范圍的整數(shù)如何輸出

    超出int范圍的整數(shù)指的是大于2147483647或小于-2147483648的整數(shù)。在計(jì)算機(jī)中,int類型是有限制的,使用32表示,能夠表示
    的頭像 發(fā)表于 11-30 11:36 ?1211次閱讀

    Yolo系列模型的部署、精度對齊與int8量化加速

    在基于PytorchQuantization導(dǎo)出的含有QDQ節(jié)點(diǎn)的onnx時,我們發(fā)現(xiàn)盡管量化版本的torch模型精度很高,但是在TensorRT部署時精度卻很低,TRT部署收精度損失很嚴(yán)重,通過
    的頭像 發(fā)表于 11-23 16:40 ?1032次閱讀

    求助,verilog中選定點(diǎn)還是浮點(diǎn)?

    數(shù)據(jù)采用定點(diǎn)整數(shù)表示,由于中間數(shù)據(jù)運(yùn)算復(fù)雜,加減乘除都有,最后導(dǎo)致結(jié)果誤差很大,精度沒辦法保證,很困惑不知道采用什么方法解決
    發(fā)表于 10-18 07:39

    浮點(diǎn)數(shù)的運(yùn)算怎么轉(zhuǎn)換成整數(shù)運(yùn)算?

    浮點(diǎn)數(shù)的運(yùn)算怎么轉(zhuǎn)換成整數(shù)運(yùn)算
    發(fā)表于 10-12 06:31