【602】语义分割评价指标 IoU mIoU precision recall F1 的计算
写在前面,关于计算时候需要注意的问题:
-
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)=|A∩B||A∪B|
IOU(A,B)=Area_of_OverlapArea_of_Union
namely,
keras 代码实现:
1 2 3 4 5 6 7 8 9 10 | 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 均交并比,其计算所有类别交集和并集之比的平均值。
默认是设置背景物体为 0,前景物体为 1(即使是 255,也会归一化为 1 的),因此在计算 Intersection 的时候,只需计算 [真值矩阵] * [预测值矩阵],然后再求和就行,因为只有两者都为 1 的情况下才会保留值。
Dice(X,Y)=2|X∩Y||X|+|Y|
DiceLoss=1−2|X∩Y|+smooth|X|+|Y|+smooth
keras 代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 防止分母为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 表示预测值
pij 表示将 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
1 2 3 4 5 6 7 8 9 10 | pred & true or pred * true or # bool 转为 int,最后以 1 和 0 显示 ((pred = = 1 ) & (true = = 1 )).astype( 'int' ) |
FN:false negative,判断为 0,但判断错误,就说明 pred 里面是 0 的像素点,true 里面是 1
1 2 3 4 5 6 | # 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
1 2 3 4 5 6 | # bool 转为 int,最后以 1 和 0 显示 ((pred = = 1 ) & (true = = 0 )).astype( 'int' ) # 1 - true 可以将 0 和 1 进行替换 # 因此就是找对应位置都为 1 的像素点了 pred * ( 1 - true) |
通过下面的函数可以分别计算 precision, recall, F1, IoU
查准率(precision),指的是预测值为1且真实值也为1的样本在预测值为1的所有样本中所占的比例。以西瓜问题为例,算法挑出来的西瓜中有多少比例是好西瓜。
分母:所有 pred 为 1 的部分
precision=TPTP+FP=Area(pred∩true)Area(pred)
召回率(recall),也叫查全率,指的是预测值为1且真实值也为1的样本在真实值为1的所有样本中所占的比例。所有的好西瓜中有多少比例被算法挑了出来。
分母:所有 true 为 1 的部分
recall=TPTP+FN=Area(pred∩true)Area(true)
F1分数(F1-Score),又称为平衡F分数(BalancedScore),它被定义为精确率和召回率的调和平均数。
F1=2∗precision∗recallprecision+recall
IOU(Intersection over Union)交并比。计算真实值和预测值集合的交集与并集之比。
IoU=TPTP+FP+FN
1 2 3 4 5 6 7 8 9 10 11 12 | 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
1 2 3 4 5 6 7 8 9 | 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
可以通过混淆矩阵进行计算
posted on 2021-07-11 22:22 McDelfino 阅读(6328) 评论(1) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2012-07-11 【058】英语词根词缀记忆大全【转】