1. 程式人生 > 其它 >NMS技術總結(NMS原理、多類別NMS、NMS的缺陷、NMS的改進思路、各種NMS方法)

NMS技術總結(NMS原理、多類別NMS、NMS的缺陷、NMS的改進思路、各種NMS方法)

 前言  本文介紹了NMS的應用場合、基本原理、多類別NMS方法和實踐程式碼、NMS的缺陷和改進思路、介紹了改進NMS的幾種常用方法、提供了其它不常用的方法的連結。

本文很早以前發過,有個讀者評論說沒有介紹多類別NMS讓他不滿意,因此特來補充。順便補充了NMS的缺點和改進思路。

歡迎關注公眾號CV技術指南,專注於計算機視覺的技術總結、最新技術跟蹤、經典論文解讀、CV招聘資訊。

Non-Maximum Suppression(NMS)非極大值抑制。從字面意思理解,抑制那些非極大值的元素,保留極大值元素。其主要用於目標檢測,目標跟蹤,3D重建,資料探勘等。

目前NMS常用的有標準NMS, Soft  NMS, DIOU NMS等。後續出現了新的Softer NMS,Weighted NMS等改進版。

原始NMS


以目標檢測為例,目標檢測推理過程中會產生很多檢測框(A,B,C,D,E,F等),其中很多檢測框都是檢測同一個目標,但最終每個目標只需要一個檢測框,NMS選擇那個得分最高的檢測框(假設是C),再將C與剩餘框計算相應的IOU值,當IOU值超過所設定的閾值(普遍設定為0.5,目標檢測中常設定為0.7,僅供參考),即對超過閾值的框進行抑制,抑制的做法是將檢測框的得分設定為0,如此一輪過後,在剩下檢測框中繼續尋找得分最高的,再抑制與之IOU超過閾值的框,直到最後會保留幾乎沒有重疊的框。這樣基本可以做到每個目標只剩下一個檢測框。

原始NMS(左圖1維,右圖2維)演算法虛擬碼如下:

實現程式碼:(以pytorch為例)

def NMS(boxes,scores, thresholds):
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]
    areas = (x2-x1)*(y2-y1)

    _,order = scores.sort(0,descending=True)
    keep = []
    while order.numel() > 0:
        i = order[0]
        keep.append(i)
        if order.numel() == 1:
            break
        xx1 = x1[order[1:]].clamp(min=x1[i])
        yy1 = y1[order[1:]].clamp(min=y1[i])
        xx2 = x2[order[1:]].clamp(max=x2[i])
        yy2 = y2[order[1:]].clamp(max=y2[i])

        w = (xx2-xx1).clamp(min=0)
        h = (yy2-yy1).clamp(min=0)
        inter = w*h

        ovr = inter/(areas[i] + areas[order[1:]] - inter)
        ids = (ovr<=thresholds).nonzero().squeeze()
        if ids.numel() == 0:
            break
        order = order[ids+1]
    return torch.LongTensor(keep)

除了自己實現以外,也可以直接使用torchvision.ops.nms來實現。

torchvision.ops.nms(boxes, scores, iou_threshold)

 

多類別NMS


上面這種做法是把所有boxes放在一起做NMS,沒有考慮類別。即某一類的boxes不應該因為它與另一類最大得分boxes的iou值超過閾值而被篩掉。

對於多類別NMS來說,它的思想比較簡單:每個類別內部做NMS就可以了。

實現方法:把每個box的座標新增一個偏移量,偏移量由類別索引來決定。

下面是torchvision.ops.batched_nms的實現原始碼以及使用方法

#實現原始碼
max_coordinate = boxes.max()
offsets = idxs.to(boxes) * (max_coordinate + torch.tensor(1).to(boxes))
boxes_for_nms = boxes + offsets[:, None]
keep = nms(boxes_for_nms, scores, iou_threshold)
return keep

#使用方法
torchvision.ops.boxes.batched_nms(boxes, scores, classes, nms_thresh)

這裡偏移量用boxes中最大的那個作為偏移基準,然後每個類別索引乘以這個基準即得到每個類的box對應的偏移量。這樣就把所有的boxes按類別分開了。

在YOLO_v5中,它自己寫了個實現的程式碼。

c = x[:, 5:6] * (0 if agnostic else max_wh)  # classes
boxes, scores = x[:, :4] + c, x[:, 4]  # boxes (offset by class), scores
i = torchvision.ops.nms(boxes, scores, iou_thres) 

這裡的max_wh相當於前面的boxes.max(),YOLO_v5中取的定值4096。這裡的agnostic用來控制是否用於多類別NMS還是普通NMS。

NMS的缺點


1. 需要手動設定閾值,閾值的設定會直接影響重疊目標的檢測,太大造成誤檢,太小達不到理想情況。

2. 低於閾值的直接設定score為0,做法太hard。

3. 只能在CPU上執行,成為影響速度的重要因素。

4. 通過IoU來評估,IoU的做法對目標框尺度和距離的影響不同。

NMS的改進思路


1. 根據手動設定閾值的缺陷,通過自適應的方法在目標係數時使用小閾值,目標稠密時使用大閾值。例如Adaptive NMS

2. 將低於閾值的直接置為0的做法太hard,通過將其根據IoU大小來進行懲罰衰減,則變得更加soft。例如Soft NMS,Softer NMS。

3. 只能在CPU上執行,速度太慢的改進思路有三個,一個是設計在GPU上的NMS,如CUDA NMS,一個是設計更快的NMS,如Fast NMS,最後一個是掀桌子,設計一個神經網路來實現NMS,如ConvNMS。

4. IoU的做法存在一定缺陷,改進思路是將目標尺度、距離引進IoU的考慮中。如DIoU。

下面稍微介紹一下這些方法中常用的一部分,另一部分僅提供連結。

Soft NMS


根據前面對目標檢測中NMS的演算法描述,易得出標準NMS容易出現的幾個問題:當閾值過小時,如下圖所示,綠色框容易被抑制;當過大時,容易造成誤檢,即抑制效果不明顯。因此,出現升級版soft NMS。

Soft NMS演算法虛擬碼如下:

標準的NMS的抑制函式如下:

    

IOU超過閾值的檢測框的得分直接設定為0,而soft NMS主張將其得分進行懲罰衰減,有兩種衰減方式,第一種懲罰函式如下:

    

這種方式使用1-Iou與得分的乘積作為衰減後的值,但這種方式在略低於閾值和略高於閾值的部分,經過懲罰衰減函式後,很容易導致得分排序的順序打亂,合理的懲罰函式應該是具有高iou的有高的懲罰,低iou的有低的懲罰,它們中間應該是逐漸過渡的。因此提出第二種高斯懲罰函式,具體如下:

這樣soft NMS可以避免閾值設定大小的問題。

Soft NMS還有後續改進版Softer-NMS,其主要解決的問題是:當所有候選框都不夠精確時該如何選擇,當得分高的候選框並不更精確,更精確的候選框得分並不是最高時怎麼選擇 。論文值得一看,本文不作更多的詳解。

此外,針對這一閾值設定問題而提出的方式還有Weighted NMS和Adaptive NMS。

Weighted NMS主要是對座標進行加權平均,實現函式如下:

其中Wi = Si *IoU(M,Bi),表示得分與IoU的乘積。

Adaptive NMS在目標分佈稀疏時使用小閾值,保證儘可能多地去除冗餘框,在目標分佈密集時採用大閾值,避免漏檢。

Softer NMS論文連結:

https://arxiv.org/abs/1809.08545

Softer NMS論文程式碼:

https://github.com/yihui-he/softer-NMS

Weighted NMS論文連結:

https://ieeexplore.ieee.org/document/8026312/

Adaptive NMS論文連結:

https://arxiv.org/abs/1904.03629

DIoU NMS


當IoU相同時,如上圖所示,當相鄰框的中心點越靠近當前最大得分框的中心點,則可認為其更有可能是冗餘框。第一種相比於第三種更不太可能是冗餘框。因此,研究者使用所提出的DIoU替代IoU作為NMS的評判準則,公式如下:

DIoU定義為DIoU=IoU-d²/c²,其中c和d的定義如下圖所示

在DIoU實際應用中還引入了引數β,用於控制對距離的懲罰程度。

當 β趨向於無窮大時,DIoU退化為IoU,此時的DIoU-NMS與標準NMS效果相當。

當 β趨向於0時,此時幾乎所有中心點與得分最大的框的中心點不重合的框都被保留了。

注:除了DIoU外,還有GIoU,CIoU,但這兩個都沒有用於NMS,而是用於座標迴歸函式,DIoU雖然本身也是用於座標迴歸,但有用於NMS的。

GIoU


GIoU的主要思想是引入將兩個框的距離。尋找能完全包圍兩個框的最小框(計算它的面積Ac)。

計算公式如下:

當兩個框完全不相交時,沒有抑制的必要。

當兩個框存在一個大框完全包圍一個小框時或大框與小框有些重合時,GIoU的大小在(-1,1)之間,不太好用來作為NMS的閾值。

GIoU的提出主要還是用於座標迴歸的loss,個人感覺用於NMS不合適,CIoU也是如此,這裡之所以提這個,是因為它與DIoU、CIoU一般都是放一起講的。

其它相關NMS


為了避免閾值設定大小、目標太密集等問題,還有一些其他方法使用神經網路去實現NMS,但並不常用,這裡只提一筆,感興趣的讀者請自行了解。如:

ConvNMS:A Convnet for Non-maximum Suppression

Pure NMS Network:Learning non-maximum suppression

Yes-Net: An effective Detector Based on Global Information

Fast NMS:

https://github.com/dbolya/yolact

Cluster NMS:

https://github.com/Zzh-tju/CIoU

Matrix NMS:

https://github.com/WXinlong/SOLO

Torchvision封裝的免編譯CUDA NMS

此處參考:

https://zhuanlan.zhihu.com/p/157900024

歡迎關注公眾號CV技術指南,專注於計算機視覺的技術總結、最新技術跟蹤、經典論文解讀、CV招聘資訊。

CV技術指南建立了一個免費的知識星球。關注公眾號新增編輯的微訊號可邀請加入。

徵稿通知:歡迎可以寫以下內容的朋友聯絡我(微訊號:“FewDesire”)。

  1. TVM入門到實踐的教程
  2. TensorRT入門到實踐的教程
  3. MNN入門到實踐的教程
  4. 數字影象處理與Opencv入門到實踐的教程
  5. OpenVINO入門到實踐的教程
  6. libtorch入門到實踐的教程
  7. Oneflow入門到實踐的教程
  8. Detectron入門到實踐的教程
  9. CUDA入門到實踐的教程
  10. caffe原始碼閱讀
  11. pytorch原始碼閱讀
  12. 深度學習從入門到精通(從卷積神經網路開始講起)
  13. 最新頂會的解讀。例如最近的CVPR2022論文。
  14. 各個方向的系統性綜述、主要模型發展演變、各個模型的創新思路和優缺點、程式碼解析等。
  15. 若自己有想寫的且這上面沒提到的,可以跟我聯絡。

宣告:有一定報酬,具體請聯絡詳談。若有想法寫但覺得自己能力不夠,也可以先聯絡本人(微訊號:FewDesire)瞭解。新增前請先備註“投稿”。

其它文章

招聘 | ​遷移科技招聘深度學習、視覺、3D視覺、機器人演算法工程師等多個職位

計算機視覺入門路線

YOLO系列梳理(一)YOLOv1-YOLOv3

YOLO系列梳理(二)YOLOv4

YOLO系列梳理(三)YOLOv5

Attention Mechanism in Computer Vision

從零搭建Pytorch模型教程(三)搭建Transformer網路

從零搭建Pytorch模型教程(二)搭建網路

從零搭建Pytorch模型教程(一)資料讀取

StyleGAN大彙總 | 全面瞭解SOTA方法、架構新進展

一份熱力圖視覺化程式碼使用教程

一份視覺化特徵圖的程式碼

工業影象異常檢測研究總結(2019-2020)

關於快速學習一項新技術或新領域的一些個人思維習慣與思想總結