7.8. 張量 I/O

引擎在輸入側接受單一張量,並在輸出側產生一個或多個張量。這些張量是 ndarray 物件,具有 numpy 章節所介紹的形狀、dtype 與描述子詞彙。它們的形狀與 dtype 來自模型檔案,並透過 input_shape / output_shapeinput_dtype / output_dtype 回報。

7.8.1. 量化

相機所執行的大多數網路是在量化的整數張量 -- int8uint8 -- 上運作,以便容納於相機的 RAM 與計算預算之內。量化張量攜帶整數值,這些值透過各張量的縮放與零點來表示實數值:

\[\text{real} = \text{scale} \times (q - \text{zero_point})\]
\[q = \mathrm{round}(\text{real} / \text{scale}) + \text{zero_point}\]

縮放與零點來自模型訓練時的校正,並儲存於模型檔案中。它們公開為 input_scaleinput_zero_pointoutput_scaleoutput_zero_point -- 各為一個列表,每個輸入或輸出張量一個項目。

ml.utils.quantize()ml.utils.dequantize() 會針對指定的輸出索引套用這些公式::

import ml.utils

real_tensor = ml.utils.dequantize(model, q_tensor, index=0)
q_tensor    = ml.utils.quantize(model, real_tensor, index=0)

當給定索引處的輸出 dtype 已是浮點數時,這兩個函式都會原樣回傳該值,因此無論模型的量化狀態為何,該呼叫都是安全的。

7.8.2. 指令碼在輸出側所見的內容

predict() 回傳的內容取決於是否註冊了後處理器。

在沒有後處理器的情況下,引擎的原始整數輸出會被自動還原量化為浮點數,並以浮點 ndarray 物件列表的形式回傳。指令碼接收到可直接讀取的實數值。對於分類網路而言這是正確的路徑,其單一輸出張量已是應用程式可逐一走訪的各類別信賴分數列表 -- 不需要解碼步驟。它也是讓未知模型快速執行起來,或從 REPL 進行臨時檢視的便捷路徑。

在註冊了後處理器的情況下(透過建構子上的 postprocess= 或 predict 呼叫上的 callback=),原始量化張量會直接交給後處理器的可呼叫物件。後處理器接收原始量化張量,並負責它所需的任何還原量化。

這個分流是一項效能上的選擇。自動還原量化會為每個輸出配置一個新的浮點張量並走訪每一個元素。一個只需要從每個張量取用少數幾個值的後處理器 -- 對信賴分數套用閾值,然後僅為通過者解碼邊界框 -- 便省去了還原量化其餘部分的成本。ml.postprocessing 下隨附的邊界框解碼器全都採取這條路徑,而 ml.utils.threshold() 正是為這種情況打造的:它接受一個量化分數張量,並回傳其還原量化後的值通過某個實數值閾值的索引,而不需還原量化整個張量。