1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        嘮一嘮對AI煉丹師的模型部署的探索

        共 7465字,需瀏覽 15分鐘

         ·

        2023-04-28 13:27

        點擊下方卡片,關注「集智書童」公眾號

        點擊加入??「集智書童」交流群

        作者丨matrix明仔@知乎 來源丨h(huán)ttps://zhuanlan.zhihu.com/p/557709588 編輯丨小書童

        1、內容介紹

        這期內容是@走走大佬關于目標檢測模型End to End推理方案的探索和嘗試。其實說到推理和部署,其實怎么也繞不開ONNX,ONNX在成立的初衷就是希望解決神經網絡在不同的訓練框架、推理框架上的轉換問題。 所以本期的內容會從如何玩轉ONNX出發(fā),嘮一嘮,我們在目標檢測部署遇到的那些事情。因為篇幅以及有部分內容我不太了解不敢亂說的關系,我會在這里對開放麥的內容做一點順序和內容上進行一點的調整,我也會加入自己的一些經歷和看法,讓大家看得更加輕松有趣一點。

        2、ONNX是什么,如何生成ONNX(ONNX簡要的介紹)?

        預告:下面用三種方法向大家介紹如何生成Relu的ONNX模型,那么哪種方法才是最強的ONNX的生成方法呢?大家可以思考一下,我們繼續(xù)往下看~

        2.1、ONNX的組成

        ONNX的靜態(tài)圖主要由「Node」(節(jié)點),「Input」(輸入)和「initializer」(初始化器)但部分所組成的。

        • 節(jié)點就代表了神經網絡模型一層的layer
        • 輸入代表了輸入矩陣的維度信息
        • 初始化器通常是存儲權重/權值的。
        • 每個組件元素都是hierarchical的結構,都是有著相互依賴關系的;
        • 這是一個雙向的鏈表。(Node、Graph彼此關聯(lián)有相互關系的);

        大家覺得難改,其實很大一部分也是因為ONNX的結構,邊與邊是一個穩(wěn)定的結構關系,彼此很大程度上是相互依賴的。所以我們具體要怎么轉化模型,怎么修改模型呢?我們接著看下去~

        2.2、Pytorch導出ONNX模型

        Pytorch是可以直接導出ONNX的模型,然后我們可以把導出的模型使用Netron的工具進行可視化工具。

        d6bbd3bd2c357eb347f0d44841c4997b.webpPytorch -> ONNX

        2.3、Numpy出發(fā),揉一個數據結構是可行嗎?

        ONNX可以在Pytorch,通過轉換得到。那么我們假如我們不用Pytorch上的轉換,從零開始直接用Numpy人手揉一個ONNX模型是可行的嗎?答案是可行的。

        ONNX是用protobuf數據格式進行保存的。而protobuf本身也是跨語言的可以支持C, C++, C#, Java, Javascript, Objective-C, PHP, Python, Ruby,使用ONN下的helper fuction就可以幫助我們順利的完成這些跨語言的轉變,所以Numpy也自然可以使用helper函數揉出輸入、節(jié)點以及初始化權值。

        2f9170906535d5ad68b677fd7b73234f.webp

        根據上圖展示的情況,可想而知要想實現一個能用的模型整體的代碼量是非??植赖摹我粋€Relu結構的代碼量就要比Pytorch的轉化(最上面的圖)實現要多將近三倍左右。(其實最大的代碼量還是出現在輸入的數據類型轉化上)如果要實現一個完整的深度模型轉化,工作量可想而知,所以我們有沒有其他的更科學高效一點的做法呢?

        2.4、ONNX GraphSurgeon Basics

        如果我們從ONNX出發(fā)要修改ONNX,其實是一個比較復雜的過程。那自然我們就會思考,那如果直接ONNX轉ONNX困難的化,能不能借助點工具,也就是有沒有更好的IR(中間表達)來幫助修改ONNX模型呢?

        沒錯「TensorRT」就已經做出來一套有效幫助Python用戶修改ONNX的工具GraphSurgeon(圖手術刀)

        這款IR主要有三部分組成

        • Tensor——分為兩個子類:變量和常量。
        • 節(jié)點——在圖中定義一個操作。可以放任何的Python 原始類型(list、dict),也可以放Graph或者Tensor。
        • 圖表——包含零個或多個節(jié)點和輸入/輸出張量。

        目的就是為了更好的編輯ONNX

        0a1ab51ea8b17c43074c7ab9d8055026.webpONNX GraphSurgeon轉化Relu結構

        有了輸入,再使用圖手術刀對模型的結構進行組合,最后完成了Relu在ONNX上的轉化。

        3、如何在 ONNX 上進行圖手術

        因為ONNX本身是一種hierarchical的設計,這種其實就是一種經典的計算機思路。當我們打算動其中一層的時候,因為上下游的關聯(lián),下游的框架也會跟著被修改。

        3.1、ONNX的IR,我們需要一個友好的中間表達!

        比如在目標檢測的場景中,我們有兩種數據標注表達「txt」「mscoco」。如果是一個區(qū)分train集和val集的工作的話,txt直接把標簽隨機分開兩組就行。但是在coco數據集上,如果需要劃分val集的時候,就要對json格式進行劃分,還需要遵循一個圖片和標注信息一一對應的關系,就會更加復雜。那ONNX的轉化也是同理,所以理論上為了簡便這個整個修改的工程,我們需要一個IR工具的一個中間表達來幫助我們進行修改。

        3.2、GraphSurgeon IR

        提供了豐富的API來幫我們進行表達。

        沒有邊的信息,邊的信息存在了輸入輸出中,所以ONNX需要對模型的信息進行拓撲排序。平時的手,我們在使用Pytorch導出ONNX模型的時候會發(fā)現有孤立的節(jié)點。如果對這個模型進行拓撲排序的話,會發(fā)現這個孤立算子是沒有意義的,應該是需要處理掉這個冗余的算子。

        3.3、TorchScript (具體的使用)

        首先Pytorch是一個動態(tài)圖,我們需要把Pytorch轉變?yōu)镺NNX的靜態(tài)圖!

        Torchscript模式主要分為Tracing和Script,區(qū)分是用「Tracing」還是「Script」,主要是看是否是動態(tài)流。

        Tracing會從頭到腳執(zhí)行一遍,記錄下來所有的函數

        如果遇到動態(tài)控制流「(if-else)Script」 會走其中的一條,執(zhí)行哪條就會記錄哪條,另一條就會忽略。并且Script對不同大小的輸入有效。

        「一般都建議Trace,因為除了ONNX_runtime,別的都不會人if這個動態(tài)算子。」

        3.4、Symbolic

        某些情況下,幫助模型在端側落地,在轉換后也能夠達到很好的效果。Python語言和c++本質上不一致,找到所以還是希望找到一種方式可以直接轉換,不用自己再手動寫C++算子,這算是一件很棒的事情。

        92f42ac2260980bfd61e466aeea16342.webp

        NMS_F是一個很平常的一個算子,在上圖的實現。如果我們用Symbolic的函數會直接轉出,整個后處理都可以用ONNX轉出來,但是這種方法

        3.5、ONNX GraphSurgeon

        272bfff38c976bc1cdb5b62876d70e9d.webp

        如何把上面的結構轉換為下面的結構,大概需要做到是吧x0的輸入分支給去掉,然后再加入LeakyReLU和Identity的節(jié)點,最后完成輸出。

        1. 先找到add的算子,把add的名字改成LeakyReLU

        2. 補充attribute屬性,加入alpha

        3. 指定一個輸出屬性identuty_out

        4. 然后再把identity節(jié)點加入到結構當中

        5. 先clean一些,再進行拓撲排序。

        5ee71e348379d886927f4837b1bf3fdf.webp操作的代碼展示

        這個任務其實也可以用ONNX原生的IR來做,但是原生IR沒有太多的幫助函數,很多工具鏈還是不太完善的,所以還是建議使用ONNX GraphSurgeon,因為用原生的IR的代碼量一頁肯定是寫不完的了。

        3.6、torch.fx

        因為這塊沒有聽太懂,所以就直接簡單的吹一些沒啥用的,大家可以放松一下看看!

        從以前的量化進化到現在也能涉及一部分的圖手術。其實為了能夠在python上也能進行圖手術上,在symbolic tracer的底層上也做了很多不一樣的工作,但是在轉化過程中也是有很多坑的,但是因為Python-to-Python會更加有利于模型訓練師的開發(fā),Pytorch的工程師也正在繼續(xù)發(fā)展,「正在逐步舍棄TorchScript」

        利用torch.fx+ONNX做量化可以極大的節(jié)省代碼量,是一個很棒的工作。

        86a346a7e332a8b418d2968f244fa5dd.webp

        4、Focus模塊替換(部署的技巧)

        Focus在yolov5提出來的!

        Focus包括了兩部分組成「Space2Depth + Conv3」。有一點值得注意的是,Focus在實現過程focus_transform中會用到Slice的動態(tài)的操作,而這種動態(tài)的操作在部署的時候往往是會出大問題的。但是有意思的一點是,Space2Depth和Pytorch中的nn.PixelUnShuffle物理意義是一致的,但是實現的過程卻有點不太相同,這也是這一版本YoloV5比較坑的點。

        但是實現上一般有 CRD/DCR mode 方式, 由排列順序決定, focus的實現跟這兩種常用的mode 均不一致

        「nn.PixelUnShuffle」是我們分割任務的老朋友了,在這里的出現,其更多的是在說明,其實下游任務正常逐步的進行一個統(tǒng)一和兼容。FPN到現在也轉變?yōu)镻AN,這樣的轉變也說明了很多。

        08dcb7041b173d4f2eadc176e1c309c3.webp48c33240f2b7fa508f8a324396ce6cca.webp

        仔細看看右邊的Focus2的內容,其實只是一個reshape+conv+reshape的操作,這在雖然物理含義上是Space2Depth,但是與ONNX和Pytorch對應的實現都是不一致的。

        mmdepoly有提供一系列的轉換,可以幫助我們更好的解釋這一點,大家可以看看。

        在yolov5-6.0的時候已經沒有人再使用Focus,這個操作也被替換成了一個6x6的卷積操作了。

        再到現在6x6的卷積會轉換為3x3的卷積拼接出來,這樣會讓整體的推理速度會更快。

        4.1、Torch.FX對Focus進行替換

        6a252812c8a905148ad328cbc5cbe8c5.webp

        主要是用自己的卷積的實現替換focus_transform和Focus的實現。把中間層展開來看的,就可以發(fā)現還需要自己手寫去補充buffer的算子。

        一個比較新的圖手術的方法,大家可以看一看,代碼量也不是很大。

        5、給目標檢測網絡插入EfficientNMS結構(如何做后處理會更加的高效?。?/span>

        其實EfficientNMS是trt8.0的一個插件,以前是BatchedNMS,這個操作還沒有手寫的插件快。

        下面就展開的講講EfficientNMS。

        EfficientNMS原本是來自谷歌的EfficientDet 來的,能提速,而且與BatchedNMS一致,這么好用,我們?yōu)樯恫挥媚兀?/p>

        Yolo系列中,卷積后會加一個Box的解碼,最后再加上NMS的操作。Box解碼需要我們去重點的優(yōu)化,如果想要在C++實現,就要自己手寫一個實現。但是在我們的實現中,我們會更多的加速方法,這里就不展開說了。但是總的來說現在的新版本的Yolo都基本都固定了前處理跟NMS部分,卷積部分和編解碼一直在變,不過現在也基本被RepVGG統(tǒng)治了。

        07c5d1e8572502ccff3c8d17b1759bfb.webp

        大家也可以看看上面實現的yolov7后處理的方法。這是一個日本的一個項目實現出的一個整體的結構,我們其實也還有另一種方式可以用pytorch+onnx直接拼出來這樣一個graph出來的。主要還是為了解決這種動態(tài)性,轉化為靜態(tài)去部署。

        6、小小的概括一下

        「EfficientNMS」該插件主要用于在 「TensorRT」 上與 「EfficientDet」 一起使用,因為這個網絡對引入的延遲特別敏感較慢的 NMS 實現。 但是,該插件對于其他檢測架構也足夠的適用,例如 SSD 或Faster RCNN。

        1. 標準 NMS 模式:僅給出兩個輸入張量,

        (1)邊界框坐標和

        (2)和每個Box的對應的分數。

        1. 融合盒解碼器模式:給出三個輸入張量,

        (1)原始每個盒子的定位預測直接來自網絡的定位頭,

        (2)相應的分類來自網絡分類頭的分數

        (3)認錨框坐標通常硬編碼為網絡中的常數張量

        7、項目的實驗結果

        這里的實驗結果大家可以看一看,這里值得注意的是居然時間要比以前沒有加操作的結構要快。其實主要原因是沒有把后處理的時間給加上,顯然這樣的快就沒有啥意義。大家要記得對比后處理的時間,如果不對比這樣的比較是不公平的,也不具有啥意義!

        7cbfc15cb15dd52e20b675430f86d1d3.webp

        8、總結

        感覺這個筆記還是沒有記錄得很到位,因為有些信息確實也是我的盲區(qū),但是整個講解過程,其實巨棒,我這里小小一篇雜談,其實還不足以記錄這么多內容,建議大家去看看開放麥的錄播,以及去了解YOLORT和MMDeploy的代碼哦~!

        https://link.zhihu.com/?target=https%3A//github.com/zhiqwang/yolov5-rt-stack

        https://link.zhihu.com/?target=https%3A//github.com/open-mmlab/mmdeploy

        c74d84bd8365e61cf2fcb63b058145ec.webp afd1184e09ad0cdf26db7fcf5896e6ae.webp

        小目標檢測技巧 | 全局上下文自適應稀疏卷積CEASA | 助力微小目標檢測漲點


        f7cab0b32cd0ae2416060925743b183f.webp

        車道線模型落地技巧 | LGAD注意力蒸餾讓模型更魯棒


        1b18a271e2bb1df2fc0ca5e2a6680dc9.webp

        目標檢測落地必備Trick | 結構化知識蒸餾讓RetinaNet再漲4個點


        掃碼加入??「集智書童」交流群

        (備注: 方向+學校/公司+昵稱

        e83f407f7633b606e30a979e1628741b.webpf7b28a4879b8bb65ad4f81906f4d6d40.webp

        18fd6a756a0ae7f9b5e5dbaf9235a80c.webp7b5f73bc58a89fbd25808010a90f67f8.webp想要了解更多:

        前沿AI視覺感知全棧知識??「分類、檢測、分割、關鍵點、車道線檢測、3D視覺(分割、檢測)、多模態(tài)、目標跟蹤、NerF

        行業(yè)技術方案??AI安防、AI醫(yī)療、AI自動駕駛 AI模型部署落地實戰(zhàn)??CUDA、TensorRT、NCNN、OpenVINO、MNN、ONNXRuntime以及地平線框架」

        歡迎掃描上方二維碼,加入集智書童-知識星球,日常分享論文、學習筆記、問題解決方案、部署方案以及全棧式答疑,期待交流!

        免責聲明 凡本公眾號注明“來源:XXX(非集智書童)”的作品,均轉載自其它媒體,版權歸原作者所有,如有侵權請聯(lián)系我們刪除,謝謝。
        點擊下方“閱讀原文”, 了解更多AI學習路上的 「武功秘籍」
        瀏覽 132
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            青青青视频在线播放 | 三上悠亚在线观看一区二区三区 | 国产亚洲综合AV婷婷 | 体内射精一区二区三区在线视频 | 国产女人18毛片水真多18精品44 | 草逼毛片 | 婷婷综合| juy824一色桃子在线观看 | 欧美第一页视频 | 毛片A级成人片 |