1. 程式人生 > 程式設計 >淺談keras中自定義二分類任務評價指標metrics的方法以及程式碼

淺談keras中自定義二分類任務評價指標metrics的方法以及程式碼

對於二分類任務,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,batch_size=10)
kfold = StratifiedKFold(Y,n_folds=num_k,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,average='micro')))
print('f1-score:{}'.format(f1_score(y,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,linewidth = 2,label='AUC=%.3f' % auc)
plt.plot([0,1],[0,'k--') # 畫一條y=x的直線,線條的顏色和型別
plt.axis([0,1.0,1.0]) # 限制座標範圍
plt.xlabel('False Postivie Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.show()

# p-r曲線針對的是二分類,這裡就不描述了
ans = classification_report(y,digits=5) # 小數點後保留5位有效數字
print(ans)

以上這篇淺談keras中自定義二分類任務評價指標metrics的方法以及程式碼就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。