keras 分割網絡自定義評估函數 - mean iou

Keras訓練網絡過程中需要實時觀察性能,mean iou不是keras自帶的評估函數,tf的又覺得不好用,自己寫了一個,經過測試沒有問題,本文記錄自定義keras mean iou評估的實現方法。

計算 IoU

用numpy計算的,作爲IoU的ground truth用作測試使用:

def iou_numpy(y_true,y_pred):
    
    intersection = np.sum(np.multiply(y_true.astype('bool'),y_pred == 1))
    union = np.sum((y_true.astype('bool')+y_pred.astype('bool'))>0)    
    
    return intersection/union

keras metric IoU

def iou_keras(y_true, y_pred):
    """
    Return the Intersection over Union (IoU).
    Args:
        y_true: the expected y values as a one-hot
        y_pred: the predicted y values as a one-hot or softmax output
    Returns:
        the IoU for the given label
    """
    label = 1
    # extract the label values using the argmax operator then
    # calculate equality of the predictions and truths to the label
    y_true = K.cast(K.equal(y_true, label), K.floatx())
    y_pred = K.cast(K.equal(y_pred, label), K.floatx())
    # calculate the |intersection| (AND) of the labels
    intersection = K.sum(y_true * y_pred)
    # calculate the |union| (OR) of the labels
    union = K.sum(y_true) + K.sum(y_pred) - intersection
    # avoid divide by zero - if the union is zero, return 1
    # otherwise, return the intersection over union
    return K.switch(K.equal(union, 0), 1.0, intersection / union)

計算 mean IoU

mean IoU 簡便起見,選取 (0,1,0.05) 作爲不同的IoU閾值,計算平均IoU

numpy 真實值計算

def mean_iou_numpy(y_true,y_pred):
    
    iou_list = []
    for thre in list(np.arange(0.0000001,0.99,0.05)):
        y_pred_temp = y_pred >= thre
        iou = iou_numpy(y_true, y_pred_temp)
        iou_list.append(iou)

    return np.mean(iou_list)

Keras mean IoU

def mean_iou_keras(y_true, y_pred):
    """
    Return the mean Intersection over Union (IoU).
    Args:
        y_true: the expected y values as a one-hot
        y_pred: the predicted y values as a one-hot or softmax output
    Returns:
        the mean IoU
    """
    label = 1
    # extract the label values using the argmax operator then
    # calculate equality of the predictions and truths to the label
    y_true = K.cast(K.equal(y_true, label), K.floatx())
    
    mean_iou = K.variable(0)
    
    thre_list = list(np.arange(0.0000001,0.99,0.05))
    
    for thre in thre_list:
        
        y_pred_temp = K.cast(y_pred >= thre, K.floatx())
        y_pred_temp = K.cast(K.equal(y_pred_temp, label), K.floatx())
        # calculate the |intersection| (AND) of the labels
        intersection = K.sum(y_true * y_pred_temp)
        # calculate the |union| (OR) of the labels
        union = K.sum(y_true) + K.sum(y_pred_temp) - intersection
        iou = K.switch(K.equal(union, 0), 1.0, intersection / union)
        mean_iou = mean_iou + iou
    
    return mean_iou / len(thre_list)

測試

## 隨機生成預測值
y_true_np = np.ones([10,10])
y_pred_np = np.random.rand(10,10)

## 真實IoU值
print(f' iou : {iou_numpy(y_true_np, y_pred_np)}')
print(f' mean_iou_numpy : {mean_iou_numpy(y_true_np, y_pred_np)}')

y_true = tf.Variable(y_true_np)
y_pred = tf.Variable(y_pred_np)

## 計算節點
iou_res = iou_keras (y_true, y_pred)
m_iou_res = mean_iou_keras (y_true, y_pred)

## 變量初始化
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init_op)
    
    ## 由於存在誤差,結果在0.0000001範圍內即可認爲相同
    
    result = sess.run(iou_res)
    print(f'result : {result} \nsame with ground truth: {abs(iou_numpy(y_true_np, y_pred_np) - result)< 0.0000001}')
    
    result = sess.run(m_iou_res)
    print(f'result : {result} \nsame with ground truth: {abs(mean_iou_numpy(y_true_np, y_pred_np) - result) < 0.0000001}')   

輸出:

iou : 0.0
mean_iou_numpy : 0.5295
result : 0.0 
same with ground truth: True
result : 0.5295000076293945 
same with ground truth: True

源碼下載

https://github.com/zywvvd/Python_Practise

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章