11.2 ONNXRuntime 簡介與使用

前言

onnx是一個開放式的格式,它還需要放到推理框架(推理引擎)上運行才可以,支援運行onnx檔的框架有ONNX RruntimeTensorRTpytorchTensorFlow等等。

在這裡就介紹onnx自帶的推理框架onnxruntime

onnxruntimeonnx官方的推理框架,它與onnx庫是完全兩個東西,安裝了onnx庫並沒有安裝上onnxruntime,它需要額外安裝。

onnxruntime分為cpu版和gpu版,兩個版本的安裝又分別是兩個庫,分別是 onnxruntime, onnxruntime-gpu

onnxruntime-gpu的安裝,又要求cudacudnn版本的嚴格匹配,否則會無法運行!這裡被坑了挺長時間,下面講講onnxruntime的安裝。

onnxruntime 安裝

對於cpu安裝,可以直接pip install onnxruntime,對於gpu版本的安裝,通常不能直接pip install onnxruntime-gpu,而是要設置指定版本,因為cudacudnn版本會限制onnxruntime的版本。

版本的對應關係如官網所示:https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#requirements

例如,cuda版本是11.4,且cudnn8.2.2.26,則可以pip install onnxruntime-gpu==1.10.0 。如果不是,那就需要配置對應版本的cudacudnn了。

通常來說,系統上cudacudnn的安裝比較麻煩,並且更換版本也不方便。這裡推薦直接在python虛擬環境中安裝指定版本的cuda, cudnn,這樣不會與系統的cudacudnn衝突。

例如:

conda install cudatoolkit=11.3 -c pytorch -c conda-forge

conda install cudnn==8.2.1

pip install onnxruntime-gpu==1.14.1

Copy

PS:需要注意的是,onnxruntimeonnxruntime-gpu不可並存,裝了onnxruntime-gpu,也是可以調用cpu的,這裡建議把onnxruntime卸載,只保留onnxruntime-gpu即可。

onnxruntime 使用

onnxruntime 中使用onnx檔,只需要將其載入到InferenceSession中,然後調用InferenceSession.run()就可以完成推理。

相比於pytorch,不需要在代碼中保留如何定義模型的的class,也不用載入權重了,這一切都存儲在onnx的計算圖中。

InferenceSession 的初始化細節如下所示

class InferenceSession(Session):

    """

    This is the main class used to run a model.

    """

 

    def __init__(self, path_or_bytes, sess_options=None, providers=None, provider_options=None, **kwargs):

        """

        :param path_or_bytes: filename or serialized ONNX or ORT format model in a byte string

        :param sess_options: session options

        :param providers: Optional sequence of providers in order of decreasing

            precedence. Values can either be provider names or tuples of

            (provider name, options dict). If not provided, then all available

            providers are used with the default precedence.

        :param provider_options: Optional sequence of options dicts corresponding

            to the providers listed in 'providers'.

Copy

在這裡,需要關注的是providers,它的作用是指定可用的設備,如["CUDAExecutionProvider", "CPUExecutionProvider", "ROCMExecutionProvider"]

ort_session_bs1 = ort.InferenceSession('resnet50_bs_1.onnx', providers=['CUDAExecutionProvider'])

inp = np.random.randn(1, 3, 224, 224).astype(np.float32)

output = model.run(['output'], {'input': inp})

Copy

完整的resnet50實現圖像分類推理,參見配套代碼,需要注意的是要與模型訓練時的前處理、後處理保持一致。

<<AI人工智慧 PyTorch自學>> 11.2 ONNX

 

onnxruntime 推理速度評估

為了觀察batchsize對推理效率的影響,這裡設計了三個模型的對比實驗,分別是bs=1 bs=128, bs為動態時,從1256的推理時延與輸送量的對比。

通常說推理速度,只看一次推理的耗時是不足以反應模型在生產時的效率的,因為推理並行的存在,因此可以採用大的batchsize來提高單位時間內,處理樣本的數量。

通常評估模型的推理的時間效率會將時延(latency)和輸送量(throughout)一起觀察。

這裡簡單介紹時延(latency)和輸送量(throughout)的意義。

時延(latency):通常用於評估使用者需要等待多長時間,根據業務場景,需要針對性保障時延,約莫等於平時說的耗時。

輸送量(throughout):用於評估伺服器一定時間內能處理的量,通常是為了提高單位時間內,能處理更多的用戶請求。

時延和輸送量通常是矛盾的,即想要高吞吐的時候,時延就會提高。

這個就像深夜的大排檔,你到店裡點一份炒河粉,需要等待多久?這取決於老闆的策略是低延時,還是高吞吐。

  • 低延時策略:來一個處理一個,儘快把你的一份河粉炒出來,需要3分鐘。
  • 高吞吐策略:稍微等等,等到3個炒河粉訂單,一次性炒出來,等了3分鐘,炒粉3分鐘,總共6分鐘,算下來,每分鐘可以炒0.5份。而低時延策略的輸送量顯然低了,每分鐘可以炒0.33份。

電腦的運行也是一樣的,可以通過batchsize來權衡時延與輸送量。


配套代碼

首先來看bs動態的模型,將bs1256的效率變化,資料如表所示:

 

bs=1

2

4

8

16

32

64

128

256

時延ms

3.7

5.2

7.7

12.9

45.4

39.1

75.9

150.3

7285.6

輸送量 frame/s

270

386

521

620

353

818

843

852

35

將輸送量繪圖如下圖所示:

<<AI人工智慧 PyTorch自學>> 11.2 ONNX

結論:

  1. 隨著batchsize的增加,輸送量逐步提高,在bs=128時,輸送量增長平緩;
  2. cpu上推理,batchsize的增加,輸送量差別不大,這也符合邏輯,畢竟cpu不是計算型處理器,無法批量處理大規模矩陣運算;
  3. 不定batchsize的模型與動態batchsize的模型,在相同batchsize下,效率並沒有什麼變化(注:由於變化沒差別,表格中沒有展示);
  4. onnruntime有一些奇怪的bs,當bs=16bs=256時,運行效率出現異常,詳情看表格;

建議:模型上線前,實際評測一下模型不同輸入時的效率,選擇合適的batchsize,可以最大化伺服器利用率。


在這裡,補充一個pytorchresnet50的推理評估資料,左圖為float32 右圖為半精度float16配套代碼

可以看到:

  • 半精度的輸送量可以提高50%左右,時延能降低30%左右。
  • 同樣的,隨著batchsize的增加,輸送量逐步提高,在bs=128時,輸送量幾乎不變。

<<AI人工智慧 PyTorch自學>> 11.2 ONNX

小結

本節介紹了onnx自帶推理框架——onnxruntime的安裝及使用,同時評估了resnet50模型在固定batch和動態batch下,以及不同batchsize時,推理的效率。

通過推理效率的評估,可以知道,batchsize到達一定的量後,輸送量飽和,因此無需追求過大的batchsize,畢竟大的batchsize,時延會增加。

這裡就有一個疑問,如何充分利用gpu資源?例如有一個計算密集型的場景,需要resnet5024小時不間斷的推理,根據上面得出來的理論,batchsize 128就可以了,gpu的顯存只需要3GB左右,對於一張16GT4而言,是否存在浪費呢?雖然gpu的利用率非常高。不知大家對此問題有什麼看法?歡迎留言評論,一起探討。

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 HCHUNGW 的頭像
    HCHUNGW

    HCHUNGW的部落格

    HCHUNGW 發表在 痞客邦 留言(0) 人氣()