TensorRT簡介--高性能深度學習支持引擎

上文簡單提到了TensorRT的基礎與onnx轉換:

基於TensorRT的神經網絡推理與加速 :https://blog.csdn.net/intflojx/article/details/81712651

後面看到老闆的slides, 感覺理解更深層次了哈,要學習的東西還有很多哈。

      摘要: 隨着傳統的高性能計算和新興的深度學習在大型的互聯網企業的普及發展,作爲訓練和推理載體的GPU也被越來越多的使用。NVDIA本着讓大家能更好地利用GPU,使其在做深度學習訓練的時候達到更好的效果的目標,推出了支持高性能深度學習支持引擎——TensorRT。

本場技術沙龍回顧鏈接:TensorRT加速深度學習在線部署

    隨着傳統的高性能計算和新興的深度學習在百度、京東等大型的互聯網企業的普及發展,作爲訓練和推理載體的GPU也被越來越多的使用。我們團隊的目標是讓大家能更好地利用GPU,使其在做深度學習訓練的時候達到更好的效果。

一、TensorRT理論解釋

       TensorRT項目立項的時候名字叫做GPU Inference Engine(簡稱GIE),Tensor表示數據流動以張量的形式。所謂張量大家可以理解爲更加複雜的高維數組,一般一維數組叫做Vector(即向量),二維數組叫做Matrix,再高緯度的就叫Tensor,Matrix其實是二維的Tensor。在TensoRT中,所有的數據都被組成最高四維的數組,如果對應到CNN中其實就是{N, C, H, W},N表示batch size,即多少張圖片或者多少個推斷(Inference)的實例;C表示channel數目;H和W表示圖像或feature maps的高度和寬度。TR表示的是Runtime。

     如果大家對深度學習有些瞭解的話可能會知道,它分爲訓練和部署兩部分,訓練部分首先也是最重要的是構建網絡結構,準備數據集,使用各種框架進行訓練,訓練要包含validation和test的過程,最後對於訓練好的模型要在實際業務中進行使用。訓練的操作一般在線下,實時數據來之後在線訓練的情況比較少,大多數情況下數據是離線的,已經收集好的,數據更新不頻繁的一天或一週一收集,數據更新頻繁的可能幾十分鐘,在線下有大規模的集羣開始對數據或模型進行更新,這樣的訓練需要消耗大量的GPU,相對而言一般會給一個比較大的batchsize,因爲它的實時性要求相對較低,一般訓練模型給的是128,甚至有些極端的1024,大的batch的好處是可以充分的利用GPU設備。但是到推斷(Inference)的時候就是不同的概念了,推斷(Inference)的時候只需要做一個前向計算,將輸入通過神經網絡得出預測的結果。而推斷(Inference)的實際部署有多種可能,可能部署在Data Center(雲端數據中心),比如說大家常見的手機上的語音輸入,目前都還是雲端的,也就是說你的聲音是傳到雲端的,雲端處理好之後把數據再返回來;還可能部署在嵌入端,比如說嵌入式的攝像頭、無人機、機器人或車載的自動駕駛,當然車載的自動駕駛可能是嵌入式的設備,也可能是一臺完整的主機,像這種嵌入式或自動駕駛,它的特點是對實時性要求很高。同樣的,Data Center也是對實時性要求很高,做一個語音識別,不能說說完了等很長時間還沒有返回,所以在線的部署最大的特點是對實時性要求很高,它對latency非常敏感,要我們能非常快的給出推斷(Inference)的結果。做一個不同恰當的比方,訓練(Training)這個階段如果模型比較慢,其實是一個砸錢可以解決的問題,我們可以用更大的集羣、更多的機器,做更大的數據並行甚至是模型並行來訓練它,重要的是成本的投入。而部署端不只是成本的問題,如果方法不得當,即使使用目前最先進的GPU,也無法滿足推斷(Inference)的實時性要求。因爲模型如果做得不好,沒有做優化,可能需要二三百毫秒才能做完一次推斷(Inference),再加上來回的網絡傳輸,用戶可能一秒後才能得到結果。在語音識別的場景之下,用戶可以等待;但是在駕駛的場景之下,可能會有性命之庾。

在部署階段,latency是非常重要的點,而TensorRT是專門針對部署端進行優化的,目前TensorRT支持大部分主流的深度學習應用,當然最擅長的是CNN(卷積神經網絡)領域,但是的TensorRT 3.0也是有RNN的API,也就是說我們可以在裏面做RNN的推斷(Inference)。

最典型的應用是圖片的分類,這也是最經典的,實際上也是深度學習目前解決的比較好的一些問題。其他的例如,圖片的語義分割、目標檢測等都是以圖片分類網絡爲基礎進行改進的。目標檢測是比較典型的例子(如下圖),訓練(Training)是對已經打好框的圖片進行前向計算,得出的框和實際的框(ground truth)進行對比,然後再做後向更新,更新模型。真正做推斷(Inference)的時候,比如一個攝像頭,基本上要保證是實時的,也就是說起碼要保證每秒25-30幀的速度,鑑於實際應用可能是二三十路攝像頭同時進來的數據,這時候必須保證一塊卡做到實時處理,還是比較有挑戰性的工作。

總結一下推斷(Inference)和訓練(Training)的不同:

1. 推斷(Inference)的網絡權值已經固定下來,無後向傳播過程,因此可以

1)模型固定,可以對計算圖進行優化

2) 輸入輸出大小固定,可以做memory優化(注意:有一個概念是fine-tuning,即訓練好的模型繼續調優,只是在已有的模型做小的改動,本質上仍然是訓練(Training)的過程,TensorRT沒有fine-tuning

2. 推斷(Inference)的batch size要小很多,仍然是latency的問題,因爲如果batch size很大,吞吐可以達到很大,比如每秒可以處理1024個batch,500毫秒處理完,吞吐可以達到2048,可以很好地利用GPU;但是推斷(Inference)不能做500毫秒處理,可以是8或者16,吞吐降低,沒有辦法很好地利用GPU.

3. 推斷(Inference)可以使用低精度的技術,訓練的時候因爲要保證前後向傳播,每次梯度的更新是很微小的,這個時候需要相對較高的精度,一般來說需要float型,如FP32,32位的浮點型來處理數據,但是在推斷(Inference)的時候,對精度的要求沒有那麼高,很多研究表明可以用低精度,如半長(16)的float型,即FP16,也可以用8位的整型(INT8)來做推斷(Inference),研究結果表明沒有特別大的精度損失,尤其對CNN。更有甚者,對Binary(二進制)的使用也處在研究過程中,即權值只有0和1。目前FP16和INT8的研究使用相對來說比較成熟。低精度計算的好處是一方面可以減少計算量,原來計算32位的單元處理FP16的時候,理論上可以達到兩倍的速度,處理INT8的時候理論上可以達到四倍的速度。當然會引入一些其他額外的操作,後面的講解中會詳細介紹FP18和INT8;另一方面是模型需要的空間減少,不管是權值的存儲還是中間值的存儲,應用更低的精度,模型大小會相應減小。

GPU卡V100添加了專門針對深度學習優化的TensorCore,TensorCore可以完成4×4矩陣的半精度乘法,也就是可以完成一個4×4的FP16矩陣和另外一個4×4的FP16矩陣相乘,當然可以再加一個矩陣(FP16 或FP32),得到一個FP32或者FP16的矩陣的過程。TensorCore在V100上理論峯值可以達到120 Tflops.(開個玩笑,電影終結者中整個天網的計算能力相當於兩塊V100)。回到圖中,先看一下如果只是用CPU來做推斷(Inference),首先它的吞吐只能達到140,也就是說每秒只能處理140張圖片,同時整個處理過程需要有14ms的延遲,也就是說用戶提交請求後,推斷(Inference)階段最快需要14ms才能返回結果;如果使用V100,在TensorFlow中去做推斷(Inference),大概是6.67ms的延時,但是吞吐只能達到305;如果使用V100加TensorRT,在保證延遲不變的情況下,吞吐可以提高15倍,高達5700張圖片每秒,這個差別是很大的。十幾倍的吞吐的提升實際上是在保證延遲的情況下成本的縮減 。

回到TensorRT的主題,之前大家普遍存在的一個疑問是在訓練過程中可以使用不同的框架,爲什麼推斷(Inference)不能用各種框架,比如TensorFlow等。當然是可以用的,但是問題是靈活性和性能是一種trade-off的關係,這是在做深度學習或訓練過程中經常會遇到的一個問題。比如像TensorFlow的設計初衷是爲各種各樣的操作來做準備的,在早期的框架,例如Caffe中很多前後處理並不在框架裏面完成,而是通過額外的程序或腳本處理,但是TensorFlow支持將所有的操作放入框架之中來完成,它提供了操作(Operation)級別的支持,使得靈活性大大提高,但是靈活性可能是以犧牲效率爲代價的。TensorFlow在實現神經網絡的過程中可以選擇各種各樣的高級庫,如用nn來搭建,tf.nn中的convolution中可以加一個卷積,可以用slim來實現卷積,不同的卷積實現效果不同,但是其對計算圖和GPU都沒有做優化,甚至在中間卷積算法的選擇上也沒有做優化,而TensorRT在這方面做了很多工作。

在講TensorRT做了哪些優化之前, 想介紹一下TensorRT的流程, 首先輸入是一個預先訓練好的FP32的模型和網絡,將模型通過parser等方式輸入到TensorRT中,TensorRT可以生成一個Serialization,也就是說將輸入串流到內存或文件中,形成一個優化好的engine,執行的時候可以調取它來執行推斷(Inference)。

TensorRT整個過程可以分三個步驟,即模型的解析(Parser),Engine優化和執行(Execution)。暫時拋開TensorRT,如果讓大家從頭寫一個深度學習模型的前向過程,具體過程應該是

1) 首先實現NN的layer,如卷積的實現,pooling的實現。

2) 管理memory,數據在各層之間如何流動。

3) 推斷(Inference)的engine來調用各層的實現。

以上三個步驟在TendorRT都已經實現好了,用戶需要做的是如何將網絡輸入到TensorRT中。目前TensorRT支持兩種輸入方式:

1. 一種是Parser的方式,即模型解析器,輸入一個caffe的模型,可以解析出其中的網絡層及網絡層之間的連接關係,然後將其輸入到TensorRT中,但是TensorRT是如何知道這些連接關係呢?答案是API。

2. API接口可以添加一個convolution或pooling。而Parser是解析模型文件,比如TensorFlow轉換成的uff,或者是caffe的模型,再用API添加到TensorRT中,構建好網絡。構建好後就可以做優化。

a) 考慮到一個情況,如果有一個網絡層不支持,這個有可能,TensorRT只支持主流的操作,比如說一個神經網絡專家開發了一個新的網絡層,新型卷積和以前的卷積都不一樣,TensorRT是不知道是做什麼的。比如說最常見的檢測網絡,有一些網絡層也是不支持的,這個時候涉及到customer layer的功能,即用戶自定義層,構建用戶自定義層需要告訴TensorRT該層的連接關係和實現方式,這樣TensorRT才能去做。

b) 目前API支持兩種接口實現方式,一種是C++,另一種是Python,Python接口可能在一些快速實現上比較方便一些。

c) Parser目前有三個,一個是caffe Parser,這個是最古老的也是支持最完善的;另一個是uff,這個是NV定義的網絡模型的一種文件結構,現在TensorFlow可以直接轉成uff;另外下一個版本3.5或4.0會支持的onnx,是Facebook主導的開源的可交換的各個框架都可以輸出的,有點類似於文檔編輯中的word格式或AutoCAD中CAD的格式,雖然是由一個公司提出,但是有希望成爲一個標準,各個APP去支持這個標準。像pytorch和caffe 2都是支持這個格式的,這個目前只在NGC (NVDIA GPU Cloud)上支持,但是下一個版本發行都會支持。如果某個公司新推出一個特別火的框架不支持怎麼辦,仍然可以採用API的方式,一層一層的添加進去,告訴TensorRT連接關係,這也是OK的。

模型解析後,engine會進行優化,具體的優化稍後會介紹。得到優化好的engine可以序列化到內存(buffer)或文件(file),讀的時候需要反序列化,將其變成engine以供使用。然後在執行的時候創建context,主要是分配預先的資源,engine加context就可以做推斷(Inference)。

以上是TensorRT的整個過程,大家在疑惑TensorRT是否支持TensorFlow,首先大家寫的網絡計算層可能都是支持的,但是有些網絡層可能不支持,在不支持的情況下可以用customer layer的方式添加進去,但是有時候爲了使用方便,可能沒辦法一層一層的去添加,需要用模型文件形式,這個取決於Parser是否完全支持。相對而言,大家在框架有過比較後會發現,caffe這個框架的特點是非常不靈活,如果要添加一個新的網絡層,需要修改源代碼;TensorFlow的優點卻是非常的靈活。

剛纔講到TensorRT所做的優化,總結下來主要有這麼幾點:

第一,也是最重要的,它把一些網絡層進行了合併。大家如果瞭解GPU的話會知道,在GPU上跑的函數叫Kernel,TensorRT是存在Kernel的調用的。在絕大部分框架中,比如一個卷積層、一個偏置層和一個激活層,這三層是需要調用三次cuDNN對應的API,但實際上這三層的實現完全是可以合併到一起的,TensorRT會對一些可以合併網絡進行合併;再比如說,目前的網絡一方面越來越深,另一方面越來越寬,可能並行做若干個相同大小的卷積,這些卷積計算其實也是可以合併到一起來做的。

第二,比如在concat這一層,比如說這邊計算出來一個1×3×24×24,另一邊計算出來1×5×24×24,concat到一起,變成一個1×8×24×24的矩陣,這個叫concat這層這其實是完全沒有必要的,因爲TensorRT完全可以實現直接接到需要的地方,不用專門做concat的操作,所以這一層也可以取消掉。

第三,Kernel可以根據不同的batch size 大小和問題的複雜程度,去選擇最合適的算法,TensorRT預先寫了很多GPU實現,有一個自動選擇的過程。

第四,不同的batch size會做tuning。

第五,不同的硬件如P4卡還是V100卡甚至是嵌入式設備的卡,TensorRT都會做優化,得到優化後的engine。

下圖是一個原始的GoogleNet的一部分,首先input後會有多個卷積,卷積完後有Bias和ReLU,結束後將結果concat(連接拼接)到一起,得到下一個input。

以上的整個過程可以做些什麼優化呢?首先是convolution, Bias和ReLU這三個操作可以合併成CBR,合併後的結果如下所示,其中包含四個1×1的CBR,一個3×3的CBR和一個5×5的CBR。

 

 

接下來可以繼續合併三個相連的1×1的CBR爲一個大的1×1的CBR(如下圖),這個合併就可以更好地利用GPU。

繼而concat層可以消除掉,直接連接到下一層的next input(如下圖)。

 

 

另外還可以做併發(Concurrency),如下圖左半部分(max pool和1×1 CBR)與右半部分(大的1×1 CBR,3×3 CBR和5×5 CBR)彼此之間是相互獨立的兩條路徑,本質上是不相關的,可以在GPU上通過併發來做,來達到的優化的目標。

 

二、TensorRT高級特徵介紹

   前面介紹了TesorRT的基礎,更多信息可以查詢官網。接下來和大家分享一些TensorRT比較高級的特徵,這塊主要針對有一定經驗或者做過一些線上部署的人。

1. 插件支持

首先TensorRT是支持插件(Plugin)的,或者前面提到的Customer layer的形式,也就是說我們在某些層TensorRT不支持的情況下,最主要是做一些檢測的操作的時候,很多層是該網絡專門定義的,TensorRT沒有支持,需要通過Plugin的形式自己去實現。實現過程包括如下兩個步驟:

1) 首先需要重載一個IPlugin的基類,生成自己的Plugin的實現,告訴GPU或TensorRT需要做什麼操作,要構建的Plugin是什麼樣子,其實就是類似於開發一個應用軟件的插件,需要在上面實現什麼功能。

2) 其次要將插件添加到合適的位置,在這裏是要添加到網絡裏去。注意,只有TensorRT 2.1和更高的版本支持插件的功能(該視頻講的時候的版本是3.0.2,支持插件功能)。

2. 低精度支持

低精度指的是之前所說過的FP16和INT8,其中FP16主要是Pascal P100和V100(tensor core)這兩張卡支持;而INT8主要針對的是 P4和P40這兩張卡,P4是專門針對線上做推斷(Inference)的小卡,和IPhone手機差不多大,75瓦的一張卡,功耗和性能非常好。

3. Python接口和更多的框架支持

TensorRT目前支持Python和C++的API,剛纔也介紹瞭如何添加,Model importer(即Parser)主要支持Caffe和Uff,其他的框架可以通過API來添加,如果在Python中調用pyTouch的API,再通過TensorRT的API寫入TensorRT中,這就完成了一個網絡的定義。

TensorRT去做推斷(Inference)的時候是不再需要框架的,用Caffe做推斷(Inference)需要Caffe這個框架,TensorRT把模型導進去後是不需要這個框架的,Caffe和TensorFlow可以通過Parser來導入,一開始就不需要安裝這個框架,給一個Caffe或TensorFlow模型,完全可以在TensorRT高效的跑起來。

三、用戶自定義層

使用插件創建用戶自定義層主要分爲兩個步驟:

第一步是創建使用IPlugin接口創建用戶自定義層,IPlugin是TensorRT中預定義的C++抽象類,用戶需要定義具體實現了什麼。

第二步是將創建的用戶自定義層添加到網絡中,如果是Caffe的模型,不支持這一層,將名字改成IPlugin是可以識別的,當然還需要一些額外的操作,說明這一層的操作是對應哪個Plugin的實現;而對於Uff是不支持Plugin的Parser,也就是說TensorFlow的模型中有一個Plugin的話,是不能從模型中識別出來的,這時候需要用到addPlugin()的方法去定義網絡中Plugin的相關信息。

IPlugin接口中需要被重載的函數有以下幾類:

1) 確定輸出:一個是通過int getNbOutput()得到output輸出的數目,即用戶所定義的一層有幾個輸出。另一個是通過Dims getOutputDimensions (int index, const Dims* inputs, int nbInputDims) 得到整個輸出的維度信息,大家可能不一定遇到有多個輸出,一般來講只有一個輸出,但是大家在做檢測網絡的時候可能會遇到多個輸出,一個輸出是實際的檢測目標是什麼,另一個輸出是目標的數目,可能的過個輸出需要設定Dimension的大小。

2) 層配置:通過void configure() 實現構建推斷(Inference) engine時模型中相應的參數大小等配置,configure()只是在構建的時候調用,這個階段確定的東西是在運行時作爲插件參數來存儲、序列化/反序列化的。

3) 資源管理:通過void Initialize()來進行資源的初始化,void terminate()來銷燬資源,甚至中間可能會有一些臨時變量,也可以使用這兩個函數進行初始化或銷燬。需要注意的是,void Initialize()和void terminate()是在整個運行時都被調用的,並不是做完一次推斷(Inference)就去調用terminate。相當於在線的一個服務,服務起的時候會調用void Initialize(),而服務止的時候調用void terminate(),但是服務會進進出出很多sample去做推斷(Inference)。

4) 執行(Execution):void enqueue()來定義用戶層的操作

5)序列化和反序列化:這個過程是將層的參數寫入到二進制文件中,需要定義一些序列化的方法。通過size_t getSerializationSize()獲得序列大小,通過void serialize()將層的參數序列化到緩存中,通過PluginSample()從緩存中將層參數反序列化。需要注意的是,TensorRT沒有單獨的反序列化的API,因爲不需要,在實習構造函數的時候就完成了反序列化的過程

6) 從Caffe Parser添加Plugin:首先通過Parsernvinfer1::IPlugin* createPlugin()實現nvcaffeparser1::IPlugin 接口,然後傳遞工廠實例到ICaffeParser::parse(),Caffe的Parser才能識別

7)運行時創建插件:通過IPlugin*createPlugin()實現nvinfer1::IPlugin接口,傳遞工廠實例:IInferRuntime::deserializeCudaEngine()

四、用戶自定義層

1. 用戶自定義層-YOLOv2實例

用一個例子YOLOv2來給大家講一下完整的流程:

準備:首先要準備 Darknet framework(https://github.com/pjreddie/darknet.git),它是一個非常小衆的cfg的形式,然後需要準備需要訓練的數據集(VOC 2007 & VOC 2012),測試的指令如下:

./darknet detector test cfg/voc.data cfg/yolo-voc-relu.cfg \

backup/yolo-voc-relu_final.weights \ data/dog.jpg

 

模型轉換:如下圖所示,根據darknet的配置文件生成caffe的prototxt文件,注意使用ReLu而不是leaky-ReLu;另外darknet中存儲順序不同,首先存儲偏移;darknet的配置文件中padding的意義不同,pad = 1表示有padding,darknet中padding的大小是Kernel的大小除以2。

 

以下是darknet cuDNN和TensorRT FP32的性能對比,FP32是4.8ms,而Darknet是11.3ms。

2. 用戶自定義層-YOLOv3實例

YOLO V3的一個重大改進在於多尺度,https://blog.csdn.net/intflojx/article/details/81452846

YOLOv3預測3種不同尺度的框(boxes),每個尺度的3個框,所以,
張量爲N×N×[3 *(4 + 1 + 80)]

網絡會在預測三種尺度的特徵N分別爲13,26,52,分別對應各三種anchor
(116×90); (156×198); (373×326)
(30×61);(62×45); (59×119);
(10×13);(16×30);(33×23);(大尺度用小anchor,提高小目標識別能力)

預測tx ty tw th

  • 對tx和ty進行sigmoid,並加上對應的offset(下圖Cx, Cy)
  • 對th和tw進行exp,並乘以對應的錨點值
  • 對tx,ty,th,tw乘以對應的步幅,即:416/13, 416 ⁄ 26, 416 ⁄ 52
  • 最後,使用sigmoid對Objectness和Classes confidence進行sigmoid得到0~1的概率,之所以用sigmoid取代之前版本的softmax,原因是softmax會擴大最大類別概率值而抑制其他類別概率值的技術。

GPU版本的圖像上採樣代碼如下(雙線性和雙三次插值的結果):

完成上採樣後,對結果進行NMS_GPU合併多尺度的結果。

五、低精度的推斷(Inference)

TensorRT通過使用Pascal GPU低精度的技術,實現高性能。以下是FP16和INT8兩種類型的性能對比。

1. FP16 推斷(Inference)

TensorRT支持高度自動化的FP16推斷(Inference),解析模型要將模型的的數據類型設置爲DataType::kHALF,同時通過builder- >setHalf2Mode(true)指令將推斷(Inference)設置爲FP16的模式。需要注意兩點,一點是FP16推斷(Inference)不需要額外的輸入,只需要輸入預先訓練好的FP32模型,另一點是目前只有Tesla P100/V100支持原生的FP16。

下圖展示了將模型從FP32轉換成FP16,並以FP16的形式存儲的過程:

 

2. INT8 推斷(Inference)

對於INT8 推斷(Inference),需要生成一個校準表來量化模型。接下來主要關注INT8推斷(Inference)的幾個方面,即:如何生成校準表,如何使用校準表,和INT8推斷(Inference)實例。

1) 如何生成校準表?

校準表的生成需要輸入有代表性的數據集, 對於分類任務TensorRT建議輸入五百張到一千張有代表性的圖片,最好每個類都要包括。生成校準表分爲兩步:第一步是將輸入的數據集轉換成batch文件;第二步是將轉換好的batch文件喂到TensorRT中來生成基於數據集的校準表,可以去統計每一層的情況。

2) 如何使用校準表?

校準這個過程如果要跑一千次是很昂貴的,所以TensorRT支持將其存入文檔,後期使用可以從文檔加載,其中存儲和加載的功能通過兩個方法來支持,即writeCalibrationCache和readCalibrationCache。最簡單的實現是從write()和read()返回值,這樣就必須每次執行都做一次校準。如果想要存儲校準時間,需要實現用戶自定義的write/read方法,具體的實現可以參考TensorRT中的simpleINT8實例。

3) INT8推斷(Inference)實例

通過下圖的實例可以發現,在YOLOv2實例中,使用TensorRT INT8做推斷(Inference)的性能可以達到2.34ms。

下圖展示了用ResNet50中FP32和INT8的性能對比,可以發現,對於P4卡,在bachsize是64的時候,INT8推斷(Inference)大概可以達到1720fps,相對於FP32有3.6倍的加速,這個是相當可觀的。

至於大家關心的精度問題對比(如下圖),INT8通過用5張圖,10張圖,50張圖去修正,精度相差基本上都是在百分之零點零幾,這個效果是非常好的。

小結一下TensorRT的優點:

1. TensorRT是一個高性能的深度學習推斷(Inference)的優化器和運行的引擎;

2. TensorRT支持Plugin,對於不支持的層,用戶可以通過Plugin來支持自定義創建;

3. TensorRT使用低精度的技術獲得相對於FP32二到三倍的加速,用戶只需要通過相應的代碼來實現。

TensorRT SDK指南:

https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#overview

NV官方利用TensorRT做的人臉識別應用:

https://github.com/AastaNV/Face-Recognition

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章