参考笔记
【机器学习】五分钟搞懂如何评价二分类模型!混淆矩阵、召回率、精确率、准确率超简单解释,入门必看!_哔哩哔哩_bilibili
混淆矩阵的概念_GIS_JH的博客-CSDN博客
机器学习中的混淆矩阵,准确率,精确率,召回率,F1,ROC/AUC,AP/MAP_混淆矩阵准确率预测精度召回率_胤风的博客-CSDN博客 课程教学资源:
8、源码分享 混淆矩阵、召回率、精准率、ROC曲线等指标一键导出【小学生都会的Pytorch】_哔哩哔哩_bilibili
上一节笔记:pytorch进阶学习(六):如何对训练好的模型进行优化、验证并且对训练过程进行准确率、损失值等的可视化,新手友好超详细记录_好喜欢吃红柚子的博客-CSDN博客
目录
一、二分类模型评价指标(理论介绍)
1. 混淆矩阵
1.1 简介
1.2 TP、FP、FN、TN
2. 二级指标
2.1 准确率
2.2 精确率
2.3 召回率
3. 三级指标 F1
二、混淆矩阵、召回率、精准率、ROC曲线等指标的可视化
1. 数据集的生成和模型的训练
2. 模型验证
2.1 具体步骤
2.2 关于eval函数的解释
2.3 代码
2.4运行结果
3. 混淆矩阵、ROC曲线等指标的图像绘制
3.1 代码
3.2 输出结果
在机器学习领域,混淆矩阵(Confusion Matrix),又称为可能性矩阵或错误矩阵。混淆矩阵是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。在图像精度评价中,主要用于比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。
在下图中:
所有样本中真正预测对的个数占所有样本的比例。
预测为正(预测是猫:4)的样本中实际上为正(实际为猫:3)的个数。
实际为正的样本中(实际为猫:5)预测为正(预测为猫:3)的有多少。
需要综合的考虑精确率和召回率两者的分数,于是引入了F1值,它是精确率和召回率的调和平均。
在这里,dataset数据集的生成和模型的训练使用到的代码和上一节一样,可以看前面的具体代码。
pytorch进阶学习(六):如何对训练好的模型进行优化、验证并且对训练过程进行准确率、损失值等的可视化,新手友好超详细记录_好喜欢吃红柚子的博客-CSDN博客
这段代码定义了一个名为eval的函数,该函数接受两个参数:dataloader和 model。函数内部首先定义了三个空列表label_list、likelihood_list和 pred_list。
代码在结果展示时运用到了进度条,需要pip一下tqdm
pip install tqdm
'''
1.单幅图片验证
2.多幅图片验证
'''
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision.models import resnet34
from utils import LoadData, write_result
import pandas as pd
from tqdm import tqdm
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '1'
def eval(dataloader, model):
label_list = []
likelihood_list = []
pred_list = []
model.eval()
with torch.no_grad():
# 加载数据加载器,得到里面的X(图片数据)和y(真实标签)
for X, y in tqdm(dataloader, desc="Model is predicting, please wait"):
# 将数据转到GPU
X = X.cuda()
# 将图片传入到模型当中就,得到预测的值pred
pred = model(X)
pred_softmax = torch.softmax(pred,1).cpu().numpy()
# 获取可能性最大的标签
label = torch.softmax(pred,1).cpu().numpy().argmax()
label_list.append(label)
# 获取可能性最大的值(即概率)
likelihood = torch.softmax(pred,1).cpu().numpy().max()
likelihood_list.append(likelihood)
pred_list.append(pred_softmax.tolist()[0])
return label_list,likelihood_list, pred_list
if __name__ == "__main__":
'''
加载预训练模型
'''
# 1. 导入模型结构
model = resnet34(pretrained=False)
num_ftrs = model.fc.in_features # 获取全连接层的输入
model.fc = nn.Linear(num_ftrs, 5) # 全连接层改为不同的输出
device = "cuda" if torch.cuda.is_available() else "cpu"
# 2. 加载模型参数
model_loc = "./BEST_resnet_epoch_50_acc_87.1.pth"
model_dict = torch.load(model_loc)
model.load_state_dict(model_dict)
model = model.to(device)
'''
加载需要预测的图片
'''
valid_data = LoadData("test.txt", train_flag=False)
test_dataloader = DataLoader(dataset=valid_data, num_workers=4, pin_memory=True, batch_size=1)
'''
获取结果
'''
# 获取模型输出
label_list, likelihood_list, pred = eval(test_dataloader, model)
# 将输出保存到exel中,方便后续分析
label_names = ["daisy", "dandelion","rose","sunflower","tulip"] # 可以把标签写在这里
df_pred = pd.DataFrame(data=pred, columns=label_names)
df_pred.to_csv('pred_result.csv', encoding='gbk', index=False)
print("Done!")
模型对test集中的866张图片进行预测,生成了pred_result.csv文件,保存着每张图片对每个类别的预测概率。
pred_result.csv展示:
需要用到sklearn包,pip安装
pip install scikit-learn
'''
模型性能度量
'''
from sklearn.metrics import * # pip install scikit-learn
import matplotlib.pyplot as plt # pip install matplotlib
import numpy as np # pip install numpy
from numpy import interp
from sklearn.preprocessing import label_binarize
import pandas as pd # pip install pandas
'''
读取数据
需要读取模型输出的标签(predict_label)以及原本的标签(true_label)
'''
target_loc = "test.txt" # 真实标签所在的文件
target_data = pd.read_csv(target_loc, sep="\t", names=["loc","type"])
true_label = [i for i in target_data["type"]]
# print(true_label)
predict_loc = "pred_result.csv" # 3.ModelEvaluate.py生成的文件
predict_data = pd.read_csv(predict_loc)#,index_col=0)
predict_label = predict_data.to_numpy().argmax(axis=1)
predict_score = predict_data.to_numpy().max(axis=1)
'''
常用指标:精度,查准率,召回率,F1-Score
'''
# 精度,准确率, 预测正确的占所有样本种的比例
accuracy = accuracy_score(true_label, predict_label)
print("精度: ",accuracy)
# 查准率P(准确率),precision(查准率)=TP/(TP+FP)
precision = precision_score(true_label, predict_label, labels=None, pos_label=1, average='macro') # 'micro', 'macro', 'weighted'
print("查准率P: ",precision)
# 查全率R(召回率),原本为对的,预测正确的比例;recall(查全率)=TP/(TP+FN)
recall = recall_score(true_label, predict_label, average='macro') # 'micro', 'macro', 'weighted'
print("召回率: ",recall)
# F1-Score
f1 = f1_score(true_label, predict_label, average='macro') # 'micro', 'macro', 'weighted'
print("F1 Score: ",f1)
'''
混淆矩阵
'''
label_names = ["daisy", "dandelion","rose","sunflower","tulip"]
confusion = confusion_matrix(true_label, predict_label, labels=[i for i in range(len(label_names))])
plt.matshow(confusion, cmap=plt.cm.Oranges) # Greens, Blues, Oranges, Reds
plt.colorbar()
for i in range(len(confusion)):
for j in range(len(confusion)):
plt.annotate(confusion[j,i], xy=(i, j), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.xticks(range(len(label_names)), label_names)
plt.yticks(range(len(label_names)), label_names)
plt.title("Confusion Matrix")
plt.show()
'''
ROC曲线(多分类)
在多分类的ROC曲线中,会把目标类别看作是正例,而非目标类别的其他所有类别看作是负例,从而造成负例数量过多,
虽然模型准确率低,但由于在ROC曲线中拥有过多的TN,因此AUC比想象中要大
'''
n_classes = len(label_names)
# binarize_predict = label_binarize(predict_label, classes=[i for i in range(n_classes)])
binarize_predict = label_binarize(true_label, classes=[i for i in range(n_classes)])
# 读取预测结果
predict_score = predict_data.to_numpy()
# 计算每一类的ROC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
fpr[i], tpr[i], _ = roc_curve(binarize_predict[:,i], [socre_i[i] for socre_i in predict_score])
roc_auc[i] = auc(fpr[i], tpr[i])
# print("roc_auc = ",roc_auc)
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(n_classes)]))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in range(n_classes):
mean_tpr += interp(all_fpr, fpr[i], tpr[i])
# Finally average it and compute AUC
mean_tpr /= n_classes
fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["macro"] = auc(fpr["macro"], tpr["macro"])
# Plot all ROC curves
lw = 2
plt.figure()
plt.plot(fpr["macro"], tpr["macro"],
label='macro-average ROC curve (area = {0:0.2f})'
''.format(roc_auc["macro"]),
color='navy', linestyle=':', linewidth=4)
for i in range(n_classes):
plt.plot(fpr[i], tpr[i], lw=lw, label='ROC curve of {0} (area = {1:0.2f})'.format(label_names[i], roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Multi-class receiver operating characteristic ')
plt.legend(loc="lower right")
plt.show()
混淆矩阵
ROC曲线