分类检测分割中的损失函数和评价指标
文章目錄
- 一、分類
- 1.1 CrossEntropy Loss
- 1.2 帶權重的交叉熵Loss
- 1.3 Focal Loss
- 二、檢測
- 2.1 L1, L2, smooth L1, IoU loss
- 2.2 評價指標
- 2.2.1 PR 曲線
- 2.2.2 AP
- 2.2.3 mAP
- 2.2.4 ROC 曲線
- 2.3 NMS
- 三、分割
- 3.1 Dice Loss
- 3.2 語義分割中的 IoU
損失函數是用來衡量真實值和預測值不一致程度的,越小越好。
一、分類
1.1 CrossEntropy Loss
信息量:用來衡量一個事件所包含的信息大小,一個事件發生的概率越大,則不確定性越小,信息量越小。公式如下,從公式中可以看出,信息量是概率的負對數:
h(x)=?log2p(x)h(x) = -log_2p(x)h(x)=?log2?p(x)
熵:用來衡量一個系統的混亂程度,代表系統中信息量的總和,是信息量的期望,信息量總和越大,表明系統不確定性就越大。
Entropy=?∑plog(p)Entropy = -\sum p log(p)Entropy=?∑plog(p)
交叉熵:用來衡量實際輸出和期望輸出的接近程度的量,交叉熵越小,兩個概率分布就越接近。
L=∑c=1Myclog(pc)L = \sum_{c=1}^My_clog(p_c)L=c=1∑M?yc?log(pc?)
其中,M表示類別數,ycy_cyc?是label,即one-hot向量,pcp_cpc?是預測概率,當M=2時,就是二元交叉熵損失
pytorch中的交叉熵:
Pytorch中CrossEntropyLoss()函數的主要是將softmax-log-NLLLoss合并到一塊得到的結果。
- Softmax后的數值都在0~1之間,所以ln之后值域是負無窮到0。
- 然后將Softmax之后的結果取log,將乘法改成加法減少計算量,同時保障函數的單調性 。
- NLLLoss的結果就是把上面的輸出與Label對應的那個值拿出來,去掉負號,再求均值。
交叉熵loss可以用到大多數語義分割場景中,但他有一個明顯的缺點,對于只用分割前景和背景時,前景數量遠遠小于背景像素的數量,損失函數中y=0的成分就會占據主導,使得模型嚴重偏向背景,導致效果不好。
語義分割 cross entropy loss計算方式:
輸入 model_output=[2, 19, 128, 256] # 19 代表輸出類別
標簽 target=[2, 512,1024]
1、將model_output的維度上采樣到 [512, 1024]
2、softmax處理:這個函數的輸入是網絡的輸出預測圖像,輸出是在dim=1(19)上計算概率。輸出維度不變,dim=1維度上的值變成了屬于每個類別的概率值。
x_softmax = F.softmax(x,dim=1)3、log處理:
log_softmax_output = torch.log(x_softmax)4、nll_loss 函數(negative log likelihood loss):這個函數目的就是把標簽圖像的元素值,作為索引值,在temp3中選擇相應的值,并求平均。
output = nn.NLLLoss(log_softmax_output, target)如果第一個點真值對應的3,則在預測結果中第3個通道去找該點的預測值,假設該點預測結果為-0.62,因為是loss前右負號,則最終結果變為0.62。其余結果依次類推,最后求均值即時最終損失結果。
- 當一個點真實類別=3時,假設其對應第三個類別的特征圖上的點為0.9,則其-log的結果非常接近0,此時loss會非常小
- 當一個點真實類別=3時,假設其對應第三個類別的特征圖上的點為0.2,則其-log的結果會比較大,此時loss會非常大
1.2 帶權重的交叉熵Loss
L=∑c=1Mwcyclog(pc)L = \sum_{c=1}^Mw_cy_clog(p_c)L=c=1∑M?wc?yc?log(pc?)
這個參數wcw_cwc?計算公式為wc=N?NcNw_c = \frac{N-N_c}{N}wc?=NN?Nc??,其中N表示總的像素格式,NcN_cNc? 表示GT類別為c的像素個數,相比原來的loss,在樣本數量不均衡的情況下可以獲得更好的效果。
1.3 Focal Loss
在one-stage檢測算法中,目標檢測器通常會產生10k數量級的框,但只有極少數是正樣本,會導致正負樣本數量不平衡以及難易樣本數量不平衡的情況,為了解決則以問題提出了focal loss。
Focal Loss是為one-stage的檢測器的分類分支服務的,它支持0或者1這樣的離散類別label。
目的是解決樣本數量不平衡的情況:
- 正樣本loss增加,負樣本loss減小
- 難樣本loss增加,簡單樣本loss減小
一般分類時候通常使用交叉熵損失:
CrossEntropy(p,y)={?log(p),y=1?log(1?p),y=0CrossEntropy(p,y)= \begin{cases} -log(p), & y=1 \\ -log(1-p), & y=0 \end{cases} CrossEntropy(p,y)={?log(p),?log(1?p),?y=1y=0?
為了解決正負樣本數量不平衡的問題,我們經常在二元交叉熵損失前面加一個參數 α\alphaα。負樣本出現的頻次多,那么就降低負樣本的權重,正樣本數量少,就相對提高正樣本的權重。因此可以通過設定α\alphaα的值來控制正負樣本對總的loss的共享權重。α\alphaα取比較小的值來降低負樣本(多的那類樣本)的權重。即:
CrossEntropy(p,y)={?αlog(p),y=1?(1?α)log(1?p),y=0CrossEntropy(p,y)= \begin{cases} -\alpha log(p), & y=1 \\ -(1-\alpha) log(1-p), & y=0 \end{cases} CrossEntropy(p,y)={?αlog(p),?(1?α)log(1?p),?y=1y=0?
雖然平衡了正負樣本的數量,但實際上,目標檢測中大量的候選目標都是易分樣本。這些樣本的損失很低,但是由于數量極不平衡,易分樣本的數量相對來講太多,最終主導了總的損失。
因此,這篇論文認為易分樣本(即,置信度高的樣本)對模型的提升效果非常小,模型應該主要關注與那些難分樣本 。一個簡單的想法就是只要我們將高置信度樣本的損失降低一些, 也即是下面的公式:
Focalloss={?(1?p)γlog(p),y=1?pγlog(1?p),y=0Focalloss = \begin{cases} -(1-p)^ \gamma log(p), & y=1 \\ -p^\gamma log(1-p), & y=0 \end{cases} Focalloss={?(1?p)γlog(p),?pγlog(1?p),?y=1y=0?
當γ=0\gamma=0γ=0 時,即為交叉熵損失函數,當其增加時,調整因子的影響也在增加,實驗發現為2時效果最優。
假設取γ=2\gamma=2γ=2,如果某個目標置信得分p=0.9,即該樣本學的非常好,那么這個樣本的權重為 (1?0.9)2=0.001(1-0.9)^2=0.001(1?0.9)2=0.001,損失貢獻降低了1000倍。
為了同時平衡正負樣本問題,Focal loss還結合了加權的交叉熵loss,所以兩者結合后得到了最終的Focal loss:
Focalloss={?α(1?p)γlog(p),y=1?(1?α)pγlog(1?p),y=0Focal loss = \begin{cases} -\alpha (1-p)^\gamma log(p), & y=1 \\ -(1-\alpha) p^\gamma log(1-p), & y=0 \end{cases} Focalloss={?α(1?p)γlog(p),?(1?α)pγlog(1?p),?y=1y=0?
取 α=0.25\alpha=0.25α=0.25 在文中,即正樣本要比負樣本占比小,這是因為負樣本易分。
單單考慮alpha的話,alpha=0.75時是最優的。但是將gamma考慮進來后,因為已經降低了簡單負樣本的權重,gamma越大,越小的alpha結果越好。最后取的是alpha=0.25,gamma=2.0
https://zhuanlan.zhihu.com/p/49981234
class FocalLoss(nn.Module):def __init__(self, gamma=0, alpha=None, size_average=True):super(FocalLoss, self).__init__()self.gamma = gammaself.alpha = alphaif isinstance(alpha,(float,int,long)): self.alpha = torch.Tensor([alpha,1-alpha])if isinstance(alpha,list): self.alpha = torch.Tensor(alpha)self.size_average = size_averagedef forward(self, input, target):if input.dim()>2:input = input.view(input.size(0),input.size(1),-1) # N,C,H,W => N,C,H*Winput = input.transpose(1,2) # N,C,H*W => N,H*W,Cinput = input.contiguous().view(-1,input.size(2)) # N,H*W,C => N*H*W,Ctarget = target.view(-1,1)logpt = F.log_softmax(input)logpt = logpt.gather(1,target)logpt = logpt.view(-1)pt = Variable(logpt.data.exp())if self.alpha is not None:if self.alpha.type()!=input.data.type():self.alpha = self.alpha.type_as(input.data)at = self.alpha.gather(0,target.data.view(-1))logpt = logpt * Variable(at)loss = -1 * (1-pt)**self.gamma * logptif self.size_average: return loss.mean()else: return loss.sum()二、檢測
檢測中有兩個任務,分類+回歸
2.1 L1, L2, smooth L1, IoU loss
L1損失:
L1(x)=∣x∣L1(x)=|x|L1(x)=∣x∣
L1損失的梯度:
ΔL1(e)Δ(e)={1,x>=0?1,otherwise\frac{\Delta L_1(e)}{\Delta(e)}= \begin{cases} 1, & x>=0 \\ -1, & otherwise \end{cases} Δ(e)ΔL1?(e)?={1,?1,?x>=0otherwise?
L2損失:
L2(x)=x2L2(x)=x^2L2(x)=x2
L2損失的梯度:
ΔL2(e)Δ(e)=2e\frac{\Delta L_2(e)}{\Delta(e)}=2e Δ(e)ΔL2?(e)?=2e
L1 Loss 相比較于L2 Loss收斂速度慢,0點處無梯度且其他位置梯度為常數,因此在極值點附近容易產生震蕩,但其對離群點的處理上要好于L2 Loss。L1 Loss與L2 Loss都沒有那么完美,因此就有了微軟RGB大神在Fast RCNN中提出的Smooth L1 Loss,公式如下:
smoothL1(x)={0.5x2,if∣x∣<1∣x∣?0.5,otherwisesmooth_{L1}(x) = \begin{cases} 0.5x^2, & if |x|<1 \\ |x|-0.5, & otherwise \end{cases} smoothL1?(x)={0.5x2,∣x∣?0.5,?if∣x∣<1otherwise?
Smooth L1 Loss特點:
- 在 e 較大時,使用的L1 Loss的形式,以防止離群點的影響;
- 在 e 較小時,使用的L2 Loss的形式,以獲得較小的梯度(收斂速度),防止在極值點附近震蕩。
smooth L1 loss 相對于 L2 loss的優點:
- 當預測框和GT差別過大時,梯度值不會過大
- 當預測框和GT差別很小時,梯度值足夠小
上面三種 Loss 用于計算目標檢測的bounding-box loss時,獨立的求出4個點的loss,然后進行相加得到最終的bounding-box loss,這種做法
IoU loss:L1 和L2 loss是將bbox四個點分別求loss然后相加,并沒有考慮靠坐標之間的相關性,而實際評價指標IOU是具備相關性。
有一些情況的 L1 loss一樣,但實際上兩個框的 IoU 有很大的不同,比如第一行的三種情況 L1 loss的值基本相當,但第三個的IoU明顯大于第一個,也就是loss和最后的評測標準其實是不一致的,所以有人提出了 IoU loss。
-
上圖展示了L2 Loss和 IoU Loss 的求法,圖中紅點表示目標檢測網絡結構中Head部分上的點(i,j)(i,j)(i,j),綠色的框表示GT框, 藍色的框表示Prediction的框。
-
IoU loss的定義如上,先求出2個框的IoU,然后再求個?ln(IoU)-ln(IoU)?ln(IoU),在實際使用中,實際很多IoU常常被定義為 IoULoss=1?IoUIoU Loss = 1-IoUIoULoss=1?IoU。
-
其中IoU是真實框和預測框的交集和并集之比,當它們完全重合時,IoU就是1,那么對于Loss來說,Loss是越小越好,說明他們重合度高,所以IoU Loss就可以簡單表示為 1- IoU。
GIoU loss:
原始的IOU存在以下問題:
- 一般的二階段網絡邊框回歸IOU≥0.5,不會對框進行回歸
- 沒有重疊,就始終為0,并且無法優化。
- 不能反映兩框是怎么相交的
GIoU可以解決1,2這類問題,能給出梯度值,在IoU基礎上加了一個懲罰項,當bbox的距離越大時,懲罰項將越大
GIoU存在的問題:
- 兩框包含的時候,GIOU會退化成IOU
- GIoU需要迭代很多次才能收斂
2.2 評價指標
- mAP: mean Average Precision, 即各類別AP的平均值
- AP: PR曲線下面積,后文會詳細講解
- PR曲線: Precision-Recall曲線
- Precision: TP / (TP + FP)
- Recall: TP / (TP + FN)
- TP: IoU>0.5的檢測框數量(同一Ground Truth只計算一次)
- FP: IoU<=0.5的檢測框,或者是檢測到同一個GT的多余檢測框的數量
- FN: 沒有檢測到的GT的數量
一般來說mAP針對整個數據集而言的;AP針對數據集中某一個類別而言的;而percision和recall針對單張圖片某一類別的。
2.2.1 PR 曲線
precision = TP/( TP+FP)
recall/TPR = TP/(TP+FN)
FPR = FP/(FP+TN)
F1 = 2TP/(2TP+FP+FN)
PR 曲線:Precision 縱軸,Recall 橫軸
如果模型的精度越高,召回率越高,那么模型的性能越好。也就是說PR曲線下面的面積越大,模型的性能越好。繪制的時候也是設定不同的分類閾值來獲得對應的坐標,從而畫出曲線。
PR 曲線特點:
- PR曲線反映了分類器對正例的識別準確程度和對正例的覆蓋能力之間的權衡。
- PR曲線有一個缺點就是會受到正負樣本比例的影響。比如當負樣本增加10倍后,在racall不變的情況下,必然召回了更多的負樣本,所以精度就會大幅下降,所以PR曲線對正負樣本分布比較敏感。對于不同正負樣本比例的測試集,PR曲線的變化就會非常大。
2.2.2 AP
AP 是以每個數據集計算一個值,也定義為 PR 曲線下的面積:
AP=∫01p(r)drAP =\int_0^1p(r) dr AP=∫01?p(r)dr
不同數據集某個類別的AP計算方法大同小異,主要有三種:
-
VOC2010之前,選取當 recall>=0, 0.1, 0.2, 1.0 這11個點時的 precision 最大值,然后將其平均就是 AP, mAP 就是所有類別 AP 的平均,也就是 AP 計算之前,會對 PR 曲線進行平滑,平滑方法為對每一個 Precision值,使用其右邊最大的precision值替代,如下圖所示:
平滑之后就變成了紅色的虛線,實際計算的時候對這11個點(0.1間隔)求平均即可。
-
VOC2010之后,需要針對每一個不同的recall值(包括0和1),選取其>=這些recall值的precision最大值,然后計算PR曲線下的面積作為AP值。
由于上述11點法插值點數過少,容易導致結果不準,一個解決方法就是內插所有點,也就是對上述平滑之后的曲線計算曲線下的面積。
-
COCO數據集,設定多個IoU閾值(0.5~0.95,step為0.005),在每個IoU閾值下的AP平均,就是所求的最終的某類別的AP值。
COCO 數據集來說,其實也是內插 AP 的計算方式,但與 VOC2008 不同的是,COCO 在 PR 曲線上采樣了 100 個點進行計算,IoU 的閾值從固定的 0.5 調整為 0.5~0.95(間隔 0.05)區間上每隔 0.05 計算一次 AP 的值,取所有結果的平均值作為最終結果。而且在 COCO 語境下,AP 就是 mAP。
-
AP50AP_{50}AP50?:IoU閾值為0.5時的AP測量值
-
AP75AP_{75}AP75?:IoU閾值為0.75時的測量值
-
APSAP_{S}APS? : 像素面積小于 32232^2322 的目標框的AP測量值
-
APMAP_{M}APM? : 像素面積在32232^2322 -96296^2962 之間目標框的測量值
-
APLAP_{L}APL? : 像素面積大于 96296^2962 的目標框的AP測量值
-
計算某個類別的 AP:
我們知道 AP 是 PR 曲線下的面積,所以首先需要繪制這個類別的 PR 曲線。
第一步:計算 Precision 和 Recall
- Precision=TP/(TP+FP)Precision = TP/(TP+FP)Precision=TP/(TP+FP)
- Recall=TP/(TP+FN)Recall = TP/(TP+FN)Recall=TP/(TP+FN)
第二步:統計 TP/FP/FN
- 通過閾值過濾掉低于置信得分閾值的預測結果
- 將剩下的框按置信得到從高到第排序
- 將得分最高的框和GT判斷其 IoU:
- 如果 IoU>th,則判定為 TP,其余框都判定為 FP
- 如果 IoU<th,則判定為FP
- 由于圖片中某個類別一共多少個 GT 我們是已知的,所以 GT-TP=FN
2.2.3 mAP
mAP 是數據集中所有類別AP的平均值
2.2.4 ROC 曲線
ROC 曲線:FPR 橫軸,TPR 縱軸
特點:
- ROC曲線有個很好的特性,當測試集中的正負樣本的分布變換的時候,ROC曲線能夠保持不變。
- ROC曲線可以反映二分類器的總體分類性能,但是無法直接從圖中識別出分類最好的閾值,事實上最好的閾值也是視具體的場景所定。ROC曲線一定在y=x之上,否則就是一個不好的分類器。
ROC曲線特點:
-
優點:當測試集中的正負樣本的分布變化的時候,ROC曲線能夠保持不變。因為TPR聚焦于正例,FPR聚焦于與負例,使其成為一個比較均衡的評估方法。
在實際的數據集中經常會出現類不平衡(class imbalance)現象,即負樣本比正樣本多很多(或者相反),而且測試數據中的正負樣本的分布也可能隨著時間變化。
-
缺點:提到ROC曲線的優點是不會隨著類別分布的改變而改變,這在某種程度上也是其缺點。因為負例N增加了很多,而曲線卻沒變,這等于產生了大量FP。像信息檢索中如果主要關心正例的預測準確性的話,這就不對了。在類別不平衡的背景下,負例的數目眾多致使FPR的增長不明顯,導致ROC曲線呈現一個過分樂觀的效果估計。ROC曲線的橫軸采用FPR,根據FPR ,當負例N的數量遠超正例P時,FP的大幅增長只能換來FPR的微小改變。結果是雖然大量負例被錯判成正例,在ROC曲線上卻無法直觀地看出來。(也可以只分析ROC曲線左邊一小段)。
PR曲線:
PR曲線使用了Precision,因此PR曲線的兩個指標都聚焦于正例。類別不平衡問題中由于主要關心正例,所以在此情況下PR曲線被廣泛認為優于ROC曲線。
使用場景:
1、ROC曲線由于兼顧正例與負例,所以適用于評估分類器的整體性能,相比而言PR曲線完全聚焦于正例。
2、如果有多份數據且存在不同的類別分布,比如信用卡欺詐問題中每個月正例和負例的比例可能都不相同,這時候如果只想單純地比較分類器的性能且剔除類別分布改變的影響,則ROC曲線比較適合,因為類別分布改變可能使得PR曲線發生變化時好時壞,這種時候難以進行模型比較;反之,如果想測試不同類別分布下對分類器的性能的影響,則PR曲線比較適合。
3、如果想要評估在相同的類別分布下正例的預測情況,則宜選PR曲線。
4、類別不平衡問題中,ROC曲線通常會給出一個樂觀的效果估計,所以大部分時候還是PR曲線更好。
5、最后可以根據具體的應用,在曲線上找到最優的點,得到相對應的precision,recall,f1 score等指標,去調整模型的閾值,從而得到一個符合具體應用的模型。
2.3 NMS
非極大值抑制:在所有預測結果中先保留得分最高的框,然后剔除掉和該框iou大于設定閾值的框
測試的時候需要做 NMS,上述的 mAP 等指標也是在做了 NMS 之后才計算的,因為訓練的時候需要大量的正負樣本來學習。
計算步驟:
- 計算出每個b-box的面積,然后根據置信度進行排序,把置信度最大的 b-box 作為對列中首個要比較的對象
- 計算其余b-box與當前最大score框的iou,丟掉iou大于設定閾值的b-box,保留小iou的框
- 重復上面過程直到走完所有候選框
三、分割
分割其實是對每個像素點進行分類,一般也就是使用分類的損失,如交叉熵等。
3.1 Dice Loss
Dice Loss:
DiceLoss=1?DiceCoefficientDice Loss = 1-Dice CoefficientDiceLoss=1?DiceCoefficient
Dice 系數:
根據 Lee Raymond Dice命名,是一種集合相似度度量函數,通常用于計算兩個樣本的相似度(值范圍為 [0, 1]),公式如下,分子有2是因為分母加了兩次TP:
DiceCoefficient=2∣X∩Y∣∣X∣+∣Y∣DiceCoefficient = \frac{2|X \cap Y|}{|X|+|Y|}DiceCoefficient=∣X∣+∣Y∣2∣X∩Y∣?
其中,∣X∣|X|∣X∣和∣Y∣|Y|∣Y∣分別表示集合的元素個數,分割任務中,兩者分別表示GT和預測。
所以 Dice Loss 公式如下:
DiceLoss=1?2∣X∩Y∣∣X∣+∣Y∣DiceLoss = 1-\frac{2|X \cap Y|}{|X|+|Y|}DiceLoss=1?∣X∣+∣Y∣2∣X∩Y∣?
從IoU過度到Dice:
- 黃色區域:預測為negative,但是GT中是positive的False Negative區域;
- 紅色區域:預測為positive,但是GT中是Negative的False positive區域;
IoU的算式:
IoU=TPTP+FP+FNIoU = \frac{TP}{TP+FP+FN}IoU=TP+FP+FNTP?
簡單的說就是,重疊的越多,IoU越接近1,預測效果越好。
Dice 系數:
DiceCoefficient=2∣X∩Y∣∣X∣+∣Y∣DiceCoefficient = \frac{2|X \cap Y|}{|X|+|Y|}DiceCoefficient=∣X∣+∣Y∣2∣X∩Y∣?
- ∣X∩Y∣|X \cap Y|∣X∩Y∣ → TPTPTP
- XXX 是 GTGTGT → TP+FNTP+FNTP+FN
- YYY 是 PredPredPred→TP+FPTP+FPTP+FP
所以:
DiceCoefficient=2×TPTP+FN+TP+FPDiceCoefficient = \frac{2 \times TP}{TP+FN+TP+FP}DiceCoefficient=TP+FN+TP+FP2×TP?
所以我們可以得到Dice和IoU之間的關系了,這里的之后的Dice默認表示Dice Coefficient:
IoU=Dice2?DiceIoU=\frac{Dice}{2-Dice}IoU=2?DiceDice?
這個函數圖像如下圖,我們只關注0~1這個區間就好了,可以發現:
- IoU和Dice同時為0,同時為1;這很好理解,就是全預測正確和全部預測錯誤
- 假設在相同的預測情況下,可以發現Dice給出的評價會比IoU高一些,哈哈哈。所以Dice的數據會更加好看一些。
需要注意的是Dice Loss存在兩個問題:
(1)訓練誤差曲線非常混亂,很難看出關于收斂的信息。盡管可以檢查在驗證集上的誤差來避開此問題。
(2)Dice Loss比較適用于樣本極度不均的情況,一般的情況下,使用 Dice Loss 會對反向傳播造成不利的影響,容易使訓練變得不穩定。
所以在一般情況下,還是使用交叉熵損失函數。
3.2 語義分割中的 IoU
IoU=TPTP+FP+FNIoU = \frac{TP}{TP+FP+FN}IoU=TP+FP+FNTP?
語義分割中,IoU是用mask來評價的:
GT:
Prediction:
Intersection:
Union:
mIoU:各個類別的IoU的均值
mIoU 的計算:
- 步驟一:先求混淆矩陣
- 步驟二:再求mIoU
混淆矩陣:
| 真實情況 | 正例 | 反例 |
| 正例 | TP | FN |
| 反例 | FP | TN |
混淆矩陣的對角線上的值表示預測正確的值,IoU是只求正例的IoU,如何找出和正例有關的混淆矩陣元素呢,可以通過劃線法來得到,
假設有N個類別,則混淆矩陣就是一個NxN的矩陣,對角表示TP,橫看真實,豎看預測。
假設一個3類的預測輸出的混淆矩陣如下所示:
| 真實 | 0 | 1 | 2 |
| 0 | 3 | 0 | 0 |
| 1 | 0 | 2 | 1 |
| 2 | 0 | 1 | 2 |
- 對角線上的元素表示預測類別正確的像素數目
- 每一行表示該類別真實的像素個數
- 每一列表示預測為該類別的像素個數
| 真實 | 0 | 1 | 2 |
| 0 | a | b | c |
| 1 | d | e | f |
| 2 | g | h | i |
精確率:
precision0=a/(a+d+g)precision_0 = a/(a+d+g)precision0?=a/(a+d+g)
precision1=e/(b+e+h)precision_1 = e/(b+e+h)precision1?=e/(b+e+h)
precision2=i/(c+f+i)precision_2 = i/(c+f+i)precision2?=i/(c+f+i)
precision0=3/(3+0+0)=1precision_0 = 3/(3+0+0)=1precision0?=3/(3+0+0)=1
precision1=2/(2+1+0)=2/3precision_1 = 2/(2+1+0)=2/3precision1?=2/(2+1+0)=2/3
precision2=2/(2+1+0)=2/3precision_2 = 2/(2+1+0)=2/3precision2?=2/(2+1+0)=2/3
召回率:
recall0=a/(a+b+c)recall_0 = a/(a+b+c)recall0?=a/(a+b+c)
recall1=e/(d+e+f)recall_1 = e/(d+e+f)recall1?=e/(d+e+f)
recall2=i/(g+h+i)recall_2 = i/(g+h+i)recall2?=i/(g+h+i)
recall0=3/(3+0+0)recall_0 = 3/(3+0+0)recall0?=3/(3+0+0)
recall1=2/(2+1+0)=2/3recall_1 = 2/(2+1+0)=2/3recall1?=2/(2+1+0)=2/3
recall2=2/(2+1+0)=2/3recall_2 = 2/(2+1+0)=2/3recall2?=2/(2+1+0)=2/3
PA:Pixel Accuracy(像素精度)→標記正確的像素占總像素的比例
PA=對角線元素之和/矩陣所有元素之和PA = 對角線元素之和/矩陣所有元素之和PA=對角線元素之和/矩陣所有元素之和
PA=3+2+23+2+2+0+0+0+0+1+1=0.78PA = \frac{3+2+2}{3+2+2+0+0+0+0+1+1}=0.78PA=3+2+2+0+0+0+0+1+13+2+2?=0.78
CPA:Class Pixel Accuracy(每類的像素精度)→按類別計算正確的像素占總像素的比例
Pi=對角線值/對應列的像素總數P_i = 對角線值/對應列的像素總數Pi?=對角線值/對應列的像素總數
p0=3/(3+0+0)=1p_0 = 3/(3+0+0) = 1p0?=3/(3+0+0)=1
p1=2/(0+2+1)=0.67p_1 = 2/(0+2+1) = 0.67p1?=2/(0+2+1)=0.67
p2=2/(0+1+2)=0.67p_2 = 2/(0+1+2) = 0.67p2?=2/(0+1+2)=0.67
MPA:Mean Pixel Accuracy→每類正確分類像素比例的平均
MPA=sum(pi)/類別數=(1+0.67+0.67)/3=0.78MPA = sum(p_i)/類別數 = (1+0.67+0.67)/3=0.78MPA=sum(pi?)/類別數=(1+0.67+0.67)/3=0.78
IoU:
-
劃線法:
IoU0=3/(3+0+0+0+0)=1IoU_0 = 3/(3+0+0+0+0) = 1IoU0?=3/(3+0+0+0+0)=1
IoU1=2/(0+2+1+1+1)=0.5IoU_1 = 2/(0+2+1+1+1) = 0.5IoU1?=2/(0+2+1+1+1)=0.5
IoU2=2/(0+1+2+2+1)=0.5IoU_2 = 2/(0+1+2+2+1) = 0.5IoU2?=2/(0+1+2+2+1)=0.5 -
代碼方法:SA∪B=SA+SB?SA∩BS_{A\cup B} = S_A+S_B-S_{A\cap B}SA∪B?=SA?+SB??SA∩B?
IoU0=3/[(3+0+0)+(3+0+0)?3]=1IoU_0 = 3/[(3+0+0)+(3+0+0) - 3] = 1IoU0?=3/[(3+0+0)+(3+0+0)?3]=1
IoU1=2/[(0+2+1)+(1+2+1)?2]=0.5IoU_1 = 2/[(0+2+1)+(1+2+1) - 2]= 0.5IoU1?=2/[(0+2+1)+(1+2+1)?2]=0.5
IoU2=2/[(0+1+2)+(0+2+1)?2]=0.5IoU_2 = 2/[(0+1+2)+(0+2+1) - 2] = 0.5IoU2?=2/[(0+1+2)+(0+2+1)?2]=0.5
mIoU:
mIoU=sum(IoUi)/classmIoU = sum(IoU_i)/classmIoU=sum(IoUi?)/class
import numpy as npclass IOUMetric:"""Class to calculate mean-iou using fast_hist method"""def __init__(self, num_classes):self.num_classes = num_classesself.hist = np.zeros((num_classes, num_classes))def _fast_hist(self, label_pred, label_true):# 找出標簽中需要計算的類別,去掉了背景mask = (label_true >= 0) & (label_true < self.num_classes)# np.bincount計算了從0到n**2-1這n**2個數中每個數出現的次數,返回值形狀(n, n)hist = np.bincount(self.num_classes * label_true[mask].astype(int) +label_pred[mask], minlength=self.num_classes ** 2).reshape(self.num_classes, self.num_classes)return hist# 輸入:預測值和真實值# 語義分割的任務是為每個像素點分配一個labeldef evaluate(self, predictions, gts):for lp, lt in zip(predictions, gts):self.hist += self._fast_hist(lp.flatten(), lt.flatten())#miouiou = np.diag(self.hist) / (self.hist.sum(axis=1) + self.hist.sum(axis=0) - np.diag(self.hist))miou = np.nanmean(iu)#其他性能指標acc = np.diag(self.hist).sum() / self.hist.sum()acc_cls = np.nanmean(np.diag(self.hist) / self.hist.sum(axis=1))freq = self.hist.sum(axis=1) / self.hist.sum()fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()return acc, acc_cls, iou, miou, fwavacc總結
以上是生活随笔為你收集整理的分类检测分割中的损失函数和评价指标的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机壳指环扣如何拆解
- 下一篇: Detectron2学习笔记