【602】語義分割評價指標 IoU mIoU precision recall F1 的計算


參考:語義分割代碼閱讀---評價指標mIoU的計算

參考:(分割網絡評價指標)dice系數和IOU之間的區別和聯系

參考:【621】numpy.array 的邏輯運算

參考:numpy.bincount詳解

參考:深度學習之語義分割中的度量標准

  寫在前面,關於計算時候需要注意的問題:

  • K.sum 在計算的時候會受到 numpy.array 的 dtype 影像,如果是 uint8 格式的話,算出的結果也是這個值,因此都是小於 255 的,具體可以參見博文:【536】K.sum 與 np.sum 的區別

  • 對於上面的情況,在計算的時候需要轉換數據類型為 int

  • 在計算 metrics 的時候,對於 除法 的運算,需要考慮分母為零的情況,因此需要添加一個 smooth 參數來消除這樣的錯誤,一般可以設置為一個很小的數,例如 1e-5
  • 需要注意的是,K.sum() 計算的結果是 tensorflow 的格式,不是具體的數字,因此需要轉換為 float 形式

  • 最終,為了簡單可以直接通過 numpy 函數來計算,但是對於自定義的 loss 函數應該是需要 K 對應的相應函數來實現

1. 二分類情況

  IoU: Intersection over Union 交並比,也叫作 Jaccard 系數

  在語義分割的問題中,這兩個集合為真實值(ground truth)和預測值(predicted segmentation),分別用 $A$ 和 $B$ 表示:

$$IOU(A, B) = \frac{|A \cap B|}{|A \cup B|}$$

$$IOU(A, B) = \frac{Area\_of\_Overlap}{Area\_of\_Union}$$

  namely,

  keras 代碼實現:

def iou(y_true, y_pred):
	# 貌似不轉成一維也可以
	y_truef = K.flatten(y_true)
	y_predf = K.flatten(y_pred)
	# 計算都是 1 的像素數
	overlap = K.sum(y_truef & y_predf)
	# 計算含有 1 的像素數
	union = K.sum(y_truef | y_predf)
	# 默認相除之后得到的是 tensor,轉為 float
	return float(overlap / union)   

                                                                

  MIoU: Mean Intersection over Union 均交並比,其計算所有類別交集和並集之比的平均值。

  參考:Dice損失函數基礎知識及代碼實現

  默認是設置背景物體為 0,前景物體為 1(即使是 255,也會歸一化為 1 的),因此在計算 Intersection 的時候,只需計算 [真值矩陣] * [預測值矩陣],然后再求和就行,因為只有兩者都為 1 的情況下才會保留值。

$$Dice(X, Y) = \frac{2|X \cap Y|}{|X| + |Y|}$$

$$DiceLoss = 1 - \frac{2|X \cap Y| + smooth}{|X| + |Y| + smooth}$$

  keras 代碼實現:

# 防止分母為0
smooth = 1e-5
 
# 定義Dice系數
def dice_coef(y_true, y_pred):
    y_truef = K.flatten(y_true)  # 將 y_true 拉為一維
    y_predf = K.flatten(y_pred)
    intersection = K.sum(y_truef * y_predf)
    return (2 * intersection + smooth) / (K.sum(y_truef) + K.sum(y_predf) + smooth)
 
 
# 定義Dice損失函數
def dice_coef_loss(y_true, y_pred):
    return 1-dice_coef(y_true, y_pred)

 

2. 一般情況

  $i$ 表示真實值

  $j$ 表示預測值

  $p_{ij}$ 表示將 $i$ 預測為 $j$

 

  對像素點進行遍歷,然后按照公式進行計算,相當於兩組矩陣進行對比,值一樣(TP)的作為分子,值不一樣的(FN+FP),但是還是包含對應的 class 的值,從而進行計算。

  FN:預測錯誤,預測為 Negative

  FP:預測錯誤,預測為 Positive

  TP:預測正確,預測為 Positive 

  直觀理解:

   

  圖中,藍色部分為TP(True Positive),紅色部分為FN(false negative),黃色部分為FP(false Positive)。根據這樣的划分,重新給出IOU公式:
  在這里插入圖片描述
  依據TP、TN、FP、FN的概念,重寫dice系數的計算公式:
  在這里插入圖片描述

  通過 keras 計算 $TP$、$FN$、$FP$,針對二分類

  $pred$:預測的值,圖片對應的 numpy.array,二維

  $true$:真實的值,圖片對應的 numpy.array,二維

  $TP$:true positive,判斷為 1,且是正確的,就是說明 $pred$ 里面是 1 的像素點,$true$ 里面也是 1

pred & true

or 

pred * true

or 

# bool 轉為 int,最后以 1 和 0 顯示
((pred == 1) & (true == 1)).astype('int')

  $FN$:false negative,判斷為 0,但判斷錯誤,就說明 $pred$ 里面是 0 的像素點,$true$ 里面是 1

# bool 轉為 int,最后以 1 和 0 顯示
((pred == 0) & (true == 1)).astype('int')

# 1 - pred 可以將 0 和 1 進行替換
# 因此就是找對應位置都為 1 的像素點了
(1 - pred) * true

  $FP$:false positive,判斷為 1,但判斷錯誤,就說明 $pred$ 里面是 1 的像素點,$true$ 里面是 0

# bool 轉為 int,最后以 1 和 0 顯示
((pred == 1) & (true == 0)).astype('int')

# 1 - true 可以將 0 和 1 進行替換
# 因此就是找對應位置都為 1 的像素點了
pred * (1 - true)

  通過下面的函數可以分別計算 $precision$, $recall$, $F_1$, $IoU$

  查准率(precision),指的是預測值為1且真實值也為1的樣本在預測值為1的所有樣本中所占的比例。以西瓜問題為例,算法挑出來的西瓜中有多少比例是好西瓜。

  分母:所有 $pred$ 為 1 的部分

$$precision = \frac{TP}{TP + FP} = \frac{Area(pred \cap true)}{Area(pred)}$$

  召回率(recall),也叫查全率,指的是預測值為1真實值也為1的樣本在真實值1的所有樣本中所占的比例。所有的好西瓜中有多少比例被算法挑了出來。

  分母:所有 $true$ 為 1 的部分

$$recall = \frac{TP}{TP + FN} = \frac{Area(pred \cap true)}{Area(true)}$$

  F1分數(F1-Score),又稱為平衡F分數(BalancedScore),它被定義為精確率和召回率的調和平均數。

$$F_1 = 2 * \frac{precision * recall}{precision + recall}$$ 

  IOU(Intersection over Union)交並比。計算真實值和預測值集合的交集與並集之比。

$$IoU = \frac{TP}{TP + FP + FN}$$

def metrics_all(pred, true):
	tp = pred & true
	fn = ((pred == 0) & (true == 1)).astype('int')
	fp = ((pred == 1) & (true == 0)).astype('int')

	precision = K.sum(tp) / (K.sum(tp) + K.sum(fp))
	recall = K.sum(tp) / (K.sum(tp) + K.sum(fn))

	f1 = 2 * precision * recall / (precision + recall)
	iou = K.sum(tp) / (K.sum(tp) + K.sum(fp) + K.sum(fn))

	return float(precision), float(recall), float(f1), float(iou)

  or

def metrics_all2(pred, true):
	tp = pred * true
	fn = (1 - pred) * true
	fp = pred * (1 - true)
	precision = K.sum(tp) / (K.sum(tp) + K.sum(fp))
	recall = K.sum(tp) / (K.sum(tp) + K.sum(fn))
	f1 = 2 * precision * recall / (precision + recall)
	iou = K.sum(tp) / (K.sum(tp) + K.sum(fp) + K.sum(fn))
	return float(precision), float(recall), float(f1), float(iou)

 

  也可以通過 np.count_nonzero(pred) 來計算非 0 像素點的個數,對於 0 和 1 表示的數組,與 np.sum(pred) 沒有區別。 

  對於多分類的問題,可以通過 np.bincount(x) 來計算每個數字的出現次數,x 需要是一維的,可以參考此鏈接 https://www.cnblogs.com/qqw-1995/p/10528237.html 

 

  可以通過混淆矩陣進行計算


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM