<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          詳細記錄YOLACT實例分割ncnn實現(xiàn)

          共 8791字,需瀏覽 18分鐘

           ·

          2022-06-28 16:49

          點擊上方小白學(xué)視覺”,選擇加"星標"或“置頂

          重磅干貨,第一時間送達

          鏈接:https://zhuanlan.zhihu.com/p/128974102
          本文轉(zhuǎn)載自知乎,作者已授權(quán),未經(jīng)許可請勿二次轉(zhuǎn)載。

           

          0x0 YOLACT實例分割


          https://urlify.cn/rURFry
          • 端到端一階段完成實例分割
          • 速度快,550x550圖片在TitanXP上號稱達到33FPS
          • 開源代碼,pytorch大法好!
          0x1 緣由
          縱觀整個github,無論是ncnn還是ncnn衍生項目,分類,檢測,定位,特征提取,OCR,風(fēng)格轉(zhuǎn)換....
          然而,就是沒有找到實例分割的例子,以至于有人發(fā)了個issue,并點名要求搞個 YOLACT 實例分割 https://github.com/Tencent/ncnn/issues/1679
          那好吧于是寫個YOLACT例子,順帶介紹下如何用ncnn實現(xiàn)類似這種需要后處理的算法

           

          0x2 pytorch測試


          YOLACT項目里有YOLACT++模型,速度更快,效果更好,不過YOLACT++用了個對部署不友好的經(jīng)典騷操作deformable convolution
          假裝沒看到,我們?nèi)ハ螺dYOLACT模型
          新建weights文件夾,下載 yolact_resnet50_54_800000.pth
          根據(jù) README 指示,先拿張圖試試看效果
          $ python eval.py --trained_model=weights/yolact_resnet50_54_800000.pth --score_threshold=0.15 --top_k=15 --image=test.jpg

          0x3 去掉后處理導(dǎo)出onnx


          直接修改 eval.py 的 evalimage,把結(jié)果展示換成 onnx export
          def evalimage(net:Yolact, path:str, save_path:str=None):    frame = torch.from_numpy(cv2.imread(path)).cuda().float()    batch = FastBaseTransform()(frame.unsqueeze(0))    preds = net(batch)
          torch.onnx._export(net, batch, "yolact.onnx", export_params=True, keep_initializers_as_inputs=True, opset_version=11)
          根據(jù)YOLACT issue中的信息,yolact.py開頭的JIT要關(guān)掉才能導(dǎo)出onnx
          # As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modulesuse_jit = False
          YOLACT后處理部分寫得非常 pythonic,這樣直接導(dǎo)出不行,要把后處理從模型剔除,方便導(dǎo)出轉(zhuǎn)換
          即便onnx能導(dǎo)出后處理,也不建議這么做
          • 后處理部分沒有標準化,每個項目作者的實現(xiàn)細節(jié)也各不相同,比如各種nms和bbox計算方式,ncnn很難用統(tǒng)一的op實現(xiàn)(caffe-ssd因為只有一種版本,所以有實現(xiàn))
          • 后處理在onnx中會轉(zhuǎn)換成一大坨膠水op,非常瑣碎,在框架中實現(xiàn)效率低下
          • onnx的大部分膠水op,ncnn不支持或有兼容問題,比如Gather等,無法直接使用
          因此,去掉后處理導(dǎo)出onnx,是正確轉(zhuǎn)換 pytorch ssd 等類似模型的通常做法
          打開yolact.py,找到 class Yolact 的 forward 方法,把 detect 過程去掉,直接返回模型的 pred_outs 輸出
           # return self.detect(pred_outs, self)            return pred_outs;
          再一次跑一遍圖片測試,不包含后處理的 yolact.onnx 出現(xiàn)了
          $ python eval.py --trained_model=weights/yolact_resnet50_54_800000.pth --score_threshold=0.15 --top_k=15 --image=test.jpg

           

          0x4 簡化onnx


          直接導(dǎo)出的onnx模型有很多膠水op是ncnn不支持的,用onnx-simplifier是常規(guī)操作
          $ pip install -U onnx --user$ pip install -U onnxruntime --user$ pip install -U onnx-simplifier --user
          $ python -m onnxsim yolact.onnx yolact-sim.onnx
          這時候遇到個問題
          Graph must be in single static assignment (SSA) form, however '523' has been used as output names multiple times
          經(jīng)過在github翻看issue,確認這是 onnx bug
          https://link.zhihu.com/?target=https%3A//github.com/onnx/onnx/issues/2613
          幸好 onnx-simplifier 已提供辦法繞過
          $ python -m onnxsim --skip-fuse-bn yolact.onnx yolact-sim.onnx 


          0x5 ncnn模型轉(zhuǎn)換和優(yōu)化


          前面簡化onnx的時候,--skip-fuse-bn 跳過了 batchnorm 合并,不過沒關(guān)系,ncnn 也有這個功能
          ncnnoptimize 工具實現(xiàn)了很多種算子融合,比如常見的 convolution-batchnorm-relu 等等
          最后的參數(shù) 0 表示fp32模型,65536 表示精簡為fp16模型,能減少模型二進制體積
          $ ./onnx2ncnn yolact-sim.onnx yolact.param yolact.bin$ ./ncnnoptimize yolact.param yolact.bin yolact-opt.param yolact-opt.bin 0


          0x6 手工微調(diào)模型

           

          還是這句話,不報錯不代表一定能用,先用netron工具打開param看看模型結(jié)構(gòu)
          這個模型輸出有四個,用紅框框出來了
          Convolution              Conv_263                 1 1 617 619 0=32 1=1 5=1 6=8192 9=1Permute                  Transpose_265            1 1 619 620 0=3UnaryOp                  Tanh_400                 1 1 814 815 0=16Concat                   Concat_401               5 1 634 673 712 751 790 816 0=-3Concat                   Concat_402               5 1 646 685 724 763 802 817 0=-3Concat                   Concat_403               5 1 659 698 737 776 815 818 0=-3Softmax                  Softmax_405              1 1 817 820 0=1 1=1
          YOLACT 的后處理需要 loc conf prior mask maskdim 這些東西
          一開始看不出這幾個輸出對應(yīng)的是什么,那么就先看shape
          ncnn::Extractor ex = yolact.create_extractor();
          ncnn::Mat in(550, 550, 3);ex.input("input.1", in);
          ncnn::Mat b620;ncnn::Mat b816;ncnn::Mat b818;ncnn::Mat b820;ex.extract("620", b620);// 32 x 138x138ex.extract("816", b816);// 4 x 19248ex.extract("818", b818);// 32 x 19248ex.extract("820", b820);// 81 x 19248
          直接編譯運行發(fā)現(xiàn) Concat 層 crash,即圖中藍框,Concat axis 參數(shù)是負數(shù) 0=-3,ncnn 還不支持
          根據(jù) Concat 多個輸入shape,發(fā)現(xiàn)是二維數(shù)據(jù)在 h axis concat,直接改成 0=0 就可以替代
          Concat                   Concat_401               5 1 634 673 712 751 790 816 0=0Concat                   Concat_402               5 1 646 685 724 763 802 817 0=0Concat                   Concat_403               5 1 659 698 737 776 815 818 0=0
          b820在softmax后面,確信是 conf,shape 81x19248 表示 81分類 x 19248個prior
          b816 shape 4x19248,對應(yīng)于每個priorbox的bbox的偏移值
          b818 shape 32x19248,根據(jù)YOLACT的后處理看,表示的是 maskdim,即32個分割熱圖的系數(shù)
          b620 shape 32x138x138,即32個分割熱圖,前面有個permute層是NCHW->NHWC的轉(zhuǎn)換 prior沒有在模型中輸出
          ncnn 處理 b620 NHWC shape 不方便,改為 extract permute 前的 NCHW 數(shù)據(jù) b619,即圖中綠框輸出
          ncnn::Extractor ex = yolact.create_extractor();
          ncnn::Mat in(550, 550, 3);ex.input("input.1", in);
          ncnn::Mat maskmaps;ncnn::Mat location;ncnn::Mat mask;ncnn::Mat confidence;ex.extract("619", maskmaps);// 138x138 x 32ex.extract("816", location);// 4 x 19248ex.extract("818", mask);// maskdim 32 x 19248ex.extract("820", confidence);// 81 x 19248


          0x7 生成prior


          原始代碼在 yolact.py class PredictionModule make_priors,增加一些 print 獲得全部 priorbox 生成規(guī)則超參
          const int conv_ws[5] = {69, 35, 18, 9, 5};const int conv_hs[5] = {69, 35, 18, 9, 5};
          const float aspect_ratios[3] = {1.f, 0.5f, 2.f};const float scales[5] = {24.f, 48.f, 96.f, 192.f, 384.f};
          YOLACT的prior四個數(shù)值是 center_x center_y box_w box_h,值域 0~1
          作者當(dāng)初寫了個bug,box_h = box_w 固定成方的了,我們也要把這個bug復(fù)現(xiàn)出來
          // make priorboxncnn::Mat priorbox(4, 19248);{    float* pb = priorbox;
          for (int p = 0; p < 5; p++) { int conv_w = conv_ws[p]; int conv_h = conv_hs[p];
          float scale = scales[p];
          for (int i = 0; i < conv_h; i++) { for (int j = 0; j < conv_w; j++) { // +0.5 because priors are in center-size notation float cx = (j + 0.5f) / conv_w; float cy = (i + 0.5f) / conv_h;
          for (int k = 0; k < 3; k++) { float ar = aspect_ratios[k];
          ar = sqrt(ar);
          float w = scale * ar / 550; float h = scale / ar / 550;
          // This is for backward compatability with a bug where I made everything square by accident // cfg.backbone.use_square_anchors: h = w;
          pb[0] = cx; pb[1] = cy; pb[2] = w; pb[3] = h;
          pb += 4; } } } }}


          0x8 YOLACT全流程實現(xiàn)


          預(yù)處理部分

          data/config.py 有 ImageNet 的 MEAN STD,BGR順序
          # These are in BGR and are for ImageNetMEANS = (103.94, 116.78, 123.68)STD   = (57.38, 57.12, 58.40)
          YOLACT實際輸入RGB,要換下順序
          const int target_size = 550;
          int img_w = bgr.cols;int img_h = bgr.rows;
          ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR2RGB, img_w, img_h, target_size, target_size);
          const float mean_vals[3] = {123.68f, 116.78f, 103.94f};const float norm_vals[3] = {1.0/58.40f, 1.0/57.12f, 1.0/57.38f};in.substract_mean_normalize(mean_vals, norm_vals);

          后處理部分

          這部分和 SSD 后處理非常類似,sort nms 這些代碼摳 ncnn/src/layer/detectionoutput.cpp
          唯一要注意的地方就是 bbox 生成和 SSD 不一樣,要用 center_x center_y box_w box_h 實現(xiàn),YOLACT原代碼在 layers/box_util.py decode 函數(shù)
          YOLACT有fastnms方法 layers/funstions/detection.py,速度更快,可我覺得普通nms畢竟是現(xiàn)成代碼,用著挺好的
          // generate all candidates for each classfor (int i=0; i<num_priors; i++){    // find class id with highest score    // start from 1 to skip background
          // ignore background or low score if (label == 0 || score <= confidence_thresh) continue;
          // apply center_size to priorbox with loc float var[4] = {0.1f, 0.1f, 0.2f, 0.2f};
          float pb_cx = pb[0]; float pb_cy = pb[1]; float pb_w = pb[2]; float pb_h = pb[3];
          float bbox_cx = var[0] * loc[0] * pb_w + pb_cx; float bbox_cy = var[1] * loc[1] * pb_h + pb_cy; float bbox_w = (float)(exp(var[2] * loc[2]) * pb_w); float bbox_h = (float)(exp(var[3] * loc[3]) * pb_h);
          float obj_x1 = bbox_cx - bbox_w * 0.5f; float obj_y1 = bbox_cy - bbox_h * 0.5f; float obj_x2 = bbox_cx + bbox_w * 0.5f; float obj_y2 = bbox_cy + bbox_h * 0.5f;
          // clip inside image
          // append object candidate}
          // merge candidate box for each classfor (int i=0; i<(int)class_candidates.size(); i++){ // sort + nms}
          // sort all result by score
          // keep_top_k

          分割圖生成

          maskmaps 實際是 32 張 138x138 尺寸的熱圖,前面輸出的每個 object 都自帶 32 個 float 系數(shù)
          object 的分割圖就是每張熱圖 * 對應(yīng)系數(shù),求和,放大到原圖尺寸,二值化,最后 crop inside 輸出框
          unnatrual很好看的! 


          0x9 補充學(xué)習(xí)資料


          噫?還有補充學(xué)習(xí)資料?
          ncnn實現(xiàn)代碼和轉(zhuǎn)好的模型已上傳到github

          https://link.zhihu.com/?target=https%3A//github.com/Tencent/ncnn

          好消息!

          小白學(xué)視覺知識星球

          開始面向外開放啦??????




          下載1:OpenCV-Contrib擴展模塊中文版教程
          在「小白學(xué)視覺」公眾號后臺回復(fù):擴展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM算法、立體視覺、目標跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺實戰(zhàn)項目52講
          小白學(xué)視覺公眾號后臺回復(fù):Python視覺實戰(zhàn)項目即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學(xué)校計算機視覺。

          下載3:OpenCV實戰(zhàn)項目20講
          小白學(xué)視覺公眾號后臺回復(fù):OpenCV實戰(zhàn)項目20講即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學(xué)習(xí)進階。

          交流群


          歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~


          瀏覽 105
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜福利美女 | 污的网站在线观看豆花视频 | 亚洲无码视频手机免费观看在线观看 | 免费a级猛片在线观看,女人毛片a级大学 | 中文字幕在线码 |