当前位置: 移动技术网 > IT编程>脚本编程>Python > 浅谈keras中自定义二分类任务评价指标metrics的方法以及代码

浅谈keras中自定义二分类任务评价指标metrics的方法以及代码

2020年06月18日  | 移动技术网IT编程  | 我要评论

稻根,中国雅虎首页,油井监控

对于二分类任务,keras现有的评价指标只有binary_accuracy,即二分类准确率,但是评估模型的性能有时需要一些其他的评价指标,例如精确率,召回率,f1-score等等,因此需要使用keras提供的自定义评价函数功能构建出针对二分类任务的各类评价指标。

keras提供的自定义评价函数功能需要以如下两个张量作为输入,并返回一个张量作为输出。

y_true:数据集真实值组成的一阶张量。

y_pred:数据集输出值组成的一阶张量。

tf.round()可对张量四舍五入,因此tf.round(y_pred)即是预测值张量。

1-tf.round(y_pred)即是预测值张量取反。

1-y_true即是真实值张量取反。

tf.reduce_sum()可对张量求和。

由此可以根据定义构建出四个基础指标tp、tn、fp、fn,然后进一步构建出进阶指标precision、recall、f1score,最后在编译阶段引用上述自定义评价指标即可。

keras中自定义二分类任务常用评价指标及其引用的代码如下

import tensorflow as tf

#精确率评价指标
def metric_precision(y_true,y_pred): 
 tp=tf.reduce_sum(y_true*tf.round(y_pred))
 tn=tf.reduce_sum((1-y_true)*(1-tf.round(y_pred)))
 fp=tf.reduce_sum((1-y_true)*tf.round(y_pred))
 fn=tf.reduce_sum(y_true*(1-tf.round(y_pred)))
 precision=tp/(tp+fp)
 return precision

#召回率评价指标
def metric_recall(y_true,y_pred): 
 tp=tf.reduce_sum(y_true*tf.round(y_pred))
 tn=tf.reduce_sum((1-y_true)*(1-tf.round(y_pred)))
 fp=tf.reduce_sum((1-y_true)*tf.round(y_pred))
 fn=tf.reduce_sum(y_true*(1-tf.round(y_pred)))
 recall=tp/(tp+fn)
 return recall

#f1-score评价指标
def metric_f1score(y_true,y_pred): 
 tp=tf.reduce_sum(y_true*tf.round(y_pred))
 tn=tf.reduce_sum((1-y_true)*(1-tf.round(y_pred)))
 fp=tf.reduce_sum((1-y_true)*tf.round(y_pred))
 fn=tf.reduce_sum(y_true*(1-tf.round(y_pred)))
 precision=tp/(tp+fp)
 recall=tp/(tp+fn)
 f1score=2*precision*recall/(precision+recall)
 return f1score

#编译阶段引用自定义评价指标示例
model.compile(optimizer='adam',
	 loss='binary_crossentropy',
	 metrics=['accuracy',
	 		metric_precision,
	 		metric_recall,
	 		metric_f1score])

补充知识:keras sklearn下两分类/多分类的技术杂谈(交叉验证和评价指标)

一.前言

这篇博客是为了记录论文补充实验中所遇到的问题,以及解决方法,主要以程序的形式呈现。

二.对象

深度学习框架:keras

研究对象:两分类/多分类

三.技术杂谈

1.k-fold交叉验证

1.概念

对一个模型进行k次训练,每次训练将整个数据集分为随机的k份,k-1作为训练集,剩余的1份作为验证集,每次训练结束将验证集上的性能指标保存下来,最后对k个结果进行平均得到最终的模型性能指标。

2.优缺点

优点:模型评估更加鲁棒

缺点:训练时间加大

3.代码

① sklearn与keras独立使用

from sklearn.model_selection import stratifiedkfold
import numpy

seed = 7 # 随机种子
numpy.random.seed(seed) # 生成固定的随机数
num_k = 5 # 多少折

# 整个数据集(自己定义)
x = 
y = 

kfold = stratifiedkfold(n_splits=num_k, shuffle=true, random_state=seed) # 分层k折,保证类别比例一致

cvscores = []
for train, test in kfold.split(x, y):

	# 可以用sequential或者function的方式建模(自己定义)
	model = 
 model.compile() # 自定义
 
	# 模型训练
 model.fit(x[train], y[train], epochs=150, batch_size=10, verbose=0)
 
 # 模型测试
 scores = model.evaluate(x[test], y[test], verbose=0)
 
 print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100)) # 打印出验证集准确率
 
 cvscores.append(scores[1] * 100)
 
print("%.2f%% (+/- %.2f%%)" % (numpy.mean(cvscores), numpy.std(cvscores))) # 输出k-fold的模型平均和标准差结果

② sklearn与keras结合使用

from keras.wrappers.scikit_learn import kerasclassifier # 使用keras下的sklearn api
from sklearn.cross_validation import stratifiedkfold, cross_val_score
import numpy as np

seed = 7 # 随机种子
numpy.random.seed(seed) # 生成固定的随机数
num_k = 5 # 多少折

# 整个数据集(自己定义)
x = 
y = 

# 创建模型
def model():
 # 可以用sequential或者function的方式建模(自己定义)
	model = 
	return model 

model = kerasclassifier(build_fn=model, epochs=150, batch_size=10)
kfold = stratifiedkfold(y, n_folds=num_k, shuffle=true, random_state=seed)
results = cross_val_score(model, x, y, cv=kfold)
print(np.average(results)) # 输出k-fold的模型平均结果

补充:引入keras的callbacks

只需要在①②中的model.fit中加入一个arg:callbacks=[keras.callbacks.modelcheckpoint()] # 这样可以保存下模型的权重,当然了你也可以使用callbacks.tensorboard保存下训练过程

2.二分类/多分类评价指标

1.概念

二分类就是说,一个目标的标签只有两种之一(例如:0或1,对应的one-hot标签为[1,0]或[0,1])。对于这种问题,一般可以采用softmax或者logistic回归来完成,分别采用cross-entropy和mse损失函数来进行网络训练,分别输出概率分布和单个的sigmoid预测值(0,1)。

多分类就是说,一个目标的标签是几种之一(如:0,1,2…)

2.评价指标

主要包含了:准确率(accuracy),错误率(error rate),精确率(precision),召回率(recall)= 真阳率(tpr)= 灵敏度(sensitivity),f1-measure(包含了micro和macro两种),假阳率(fpr),特异度(specificity),roc(receiver operation characteristic curve)(包含了micro和macro两种),auc(area under curve),p-r曲线(precision-recall),混淆矩阵

① 准确率和错误率

accuracy = (tp+tn)/ (p+n)或者accuracy = (tp+tn)/ (t+f)

error rate = (fp+fn) / (p+n)或者(fp+fn) / (t+f)

accuracy = 1 - error rate

可见:准确率、错误率是对分类器在整体数据上的评价指标。

② 精确率

precision=tp /(tp+fp)

可见:精确率是对分类器在预测为阳性的数据上的评价指标。

③ 召回率/真阳率/灵敏度

recall = tpr = sensitivity = tp/(tp+fn)

可见:召回率/真阳率/灵敏度是对分类器在整个阳性数据上的评价指标。

④ f1-measure

f1-measure = 2 * (recall * precision / (recall + precision))

包含两种:micro和macro(对于多类别分类问题,注意区别于多标签分类问题)

1)micro

计算出所有类别总的precision和recall,然后计算f1-measure

2)macro

计算出每一个类的precison和recall后计算f1-measure,最后将f1-measure平均

可见:f1-measure是对两个矛盾指标precision和recall的一种调和。

⑤ 假阳率

fpr=fp / (fp+tn)

可见:假阳率是对分类器在整个阴性数据上的评价指标,针对的是假阳。

⑥ 特异度

specificity = 1- fpr

可见:特异度是对分类器在整个阴性数据上的评价指标,针对的是真阴。

⑦ roc曲线和auc

作用:灵敏度与特异度的综合指标

横坐标:fpr/1-specificity

纵坐标:tpr/sensitivity/recall

auc是roc右下角的面积,越大,表示分类器的性能越好

包含两种:micro和macro(对于多类别分类问题,注意区别于多标签分类问题)

假设一共有m个样本,n个类别。预测出来的概率矩阵p(m,n),标签矩阵l (m,n)

1)micro

根据p和l中的每一列(对整个数据集而言),计算出各阈值下的tpr和fpr,总共可以得到n组数据,分别画出n个roc曲线,最后取平均

2)macro

将p和l按行展开,然后转置为两列,最后画出一个roc曲线

⑧ p-r曲线

横轴:recall

纵轴:precision

评判:1)直观看,p-r包围的面积越大越好,p=r的点越大越好;2)通过f1-measure来看

比较roc和p-r: 当样本中的正、负比例不平衡的时候,roc曲线基本保持不变,而p-r曲线变化很大,原因如下:

当负样本的比例增大时,在召回率一定的情况下,那么表现较差的模型必然会召回更多的负样本,tp降低,fp迅速增加(对于性能差的分类器而言),precision就会降低,所以p-r曲线包围的面积会变小。

⑨ 混淆矩阵

行表示的是样本中的一种真类别被预测的结果,列表示的是一种被预测的标签所对应的真类别。

3.代码

注意:以下的代码是合在一起写的,有注释。

from sklearn import datasets
import numpy as np
from sklearn.preprocessing import label_binarize
from sklearn.linear_model import logisticregression
from sklearn.metrics import confusion_matrix, precision_score, accuracy_score,recall_score, f1_score,roc_auc_score, precision_recall_fscore_support, roc_curve, classification_report
import matplotlib.pyplot as plt

iris = datasets.load_iris()
x, y = iris.data, iris.target
print("label:", y)
n_class = len(set(iris.target))
y_one_hot = label_binarize(y, np.arange(n_class))

# alpha = np.logspace(-2, 2, 20) #设置超参数范围
# model = logisticregressioncv(cs = alpha, cv = 3, penalty = 'l2') #使用l2正则化
model = logisticregression() # 内置了最大迭代次数了,可修改
model.fit(x, y)
y_score = model.predict(x) # 输出的是整数标签
mean_accuracy = model.score(x, y)
print("mean_accuracy: ", mean_accuracy)
print("predict label:", y_score)
print(y_score==y)
print(y_score.shape)
y_score_pro = model.predict_proba(x) # 输出概率
print(y_score_pro)
print(y_score_pro.shape)
y_score_one_hot = label_binarize(y_score, np.arange(n_class)) # 这个函数的输入必须是整数的标签哦
print(y_score_one_hot.shape)

obj1 = confusion_matrix(y, y_score) # 注意输入必须是整数型的,shape=(n_samples, )
print('confusion_matrix\n', obj1)

print(y)
print('accuracy:{}'.format(accuracy_score(y, y_score))) # 不存在average
print('precision:{}'.format(precision_score(y, y_score,average='micro')))
print('recall:{}'.format(recall_score(y, y_score,average='micro')))
print('f1-score:{}'.format(f1_score(y, y_score,average='micro')))
print('f1-score-for-each-class:{}'.format(precision_recall_fscore_support(y, y_score))) # for macro
# print('auc y_pred = one-hot:{}\n'.format(roc_auc_score(y_one_hot, y_score_one_hot,average='micro'))) # 对于multi-class输入必须是proba,所以这种是错误的

# auc值
auc = roc_auc_score(y_one_hot, y_score_pro,average='micro') # 使用micro,会计算n_classes个roc曲线,再取平均
print("auc y_pred = proba:", auc)
# 画roc曲线
print("one-hot label ravelled shape:", y_one_hot.ravel().shape)
fpr, tpr, thresholds = roc_curve(y_one_hot.ravel(),y_score_pro.ravel()) # ravel()表示平铺开来,因为输入的shape必须是(n_samples,)
print("threshold: ", thresholds)
plt.plot(fpr, tpr, linewidth = 2,label='auc=%.3f' % auc)
plt.plot([0,1],[0,1], 'k--') # 画一条y=x的直线,线条的颜色和类型
plt.axis([0,1.0,0,1.0]) # 限制坐标范围
plt.xlabel('false postivie rate')
plt.ylabel('true positive rate')
plt.legend()
plt.show()

# p-r曲线针对的是二分类,这里就不描述了
ans = classification_report(y, y_score,digits=5) # 小数点后保留5位有效数字
print(ans)

以上这篇浅谈keras中自定义二分类任务评价指标metrics的方法以及代码就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网