图片2分类卷积神经网络模型训练、分类预测案例全过程(2)
前言
训练好的模型的调用和实际图片的分类预测,这里包括数据预处理和模型调用。
# 一、数据预处理
用于开展分类预测的数据量一般不是很大,这里就没有再制作tfrecord格式数据,直接使用文件夹里面的图片开展分类预测。
这里需要一个加载读取单张图片的函数,具体如下。用于后期文件夹中所有图片的读取。
def load_preprocess_image_for_prediction(img_path):
'''图像加载、预处理for predictation, 参数为图像绝对路径'''
img_da = tf.io.read_file(img_path)
img_da = tf.image.decode_jpeg(img_da, channels=3)
img_da = tf.image.resize(img_da, [256, 256])
img_da = tf.cast(img_da, tf.float32)
img_da = img_da/255
return img_da
二、混淆矩阵计算及其图片绘制
1.混淆矩阵计算
代码如下:
def predict_result_confused_matrix(y_true, y_predict):
'''混淆矩阵函数
两个输入参数分别为真实结果、预测结果
return值----t_n True Negative/真阴性
f_p False Positive/假阳性
f_n False Negative/假阴性
t_p True Postive/真阳性
accuracy 预测正确的所有结个数所占比例
precision 精准率
recall 召回率'''
t_n, f_p, f_n, t_p = confusion_matrix(y_true, y_predict, labels=None, sample_weight=None, normalize=None).ravel()
accuracy = round((t_n + t_p)/(t_n + f_p + f_n + t_p), 4)
precision = round(t_n/(t_n + f_n), 4)
recall = round(t_n/(t_n + f_p), 4)
F1_measure = round(2*precision*recall/(precision + recall), 4)
return [t_n, f_p, f_n, t_p, accuracy, precision, recall, F1_measure]
2.混淆矩阵图片绘制
代码如下:
def draw_confusion_matrix(_input_excel_data, _sheet_name='Predicted_result', dpi_value=100):
'''_input_excel_data是excel文件的绝对路径
_sheet_name='Predicted_result是excel文件中存放实测值、预测值的sheet名
dpi_value是导出的图片的分辨率大小,默认值是100
混淆矩阵图片导出位置与输入excel文件路径相同'''
excel_df = pd.read_excel(_input_excel_data, sheet_name=_sheet_name)
_y_true = excel_df[['True_labels']].values.flatten()
_y_pred = excel_df[['Predict_labels']].values.flatten()
_classes = list(set(_y_pred))
_confusion_matrix_resluts = confusion_matrix(_y_true, _y_pred, labels=None, sample_weight=None, normalize=None).ravel().reshape(2, 2)
_text_list = [['dis预测为dis','dis预测为undis'],['undis预测为dis','undis预测为undis']]
# 解决plt中文显示乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.figure(dpi=dpi_value)
plt.imshow(_confusion_matrix_resluts, cmap=plt.cm.tab20c)
_indices=range(len(_confusion_matrix_resluts))
plt.title(str(os.path.basename(_input_excel_data).split(".")[0]), fontsize=13)
plt.xticks(_indices, _classes, fontsize=12)
plt.yticks(_indices, _classes, fontsize=12)
plt.colorbar()
plt.xlabel('Predict value', fontsize=15)
plt.ylabel('True value', fontsize=15)
for first_index in range(len(_confusion_matrix_resluts)):
for second_index in range(len(_confusion_matrix_resluts[first_index])):
str1 = _confusion_matrix_resluts[first_index][second_index]
str2 = _text_list[first_index][second_index]
strs = str2 + ':' + str(str1)
plt.text(first_index, second_index, strs, horizontalalignment="center",fontsize=10)
# plt.show()
# 生成图片导出的绝对路径
_path = os.path.dirname(_input_excel_data)
_name = os.path.basename(_input_excel_data).split(".")[0] + '__混淆矩阵结果' + '.png'
_png_save_abspath = os.path.join(_path, _name)
plt.savefig(_png_save_abspath)
三、模型调用及图片分类预测函数
模型调用我直接写到一个函数中,这样方便使用。具体看如下代码:
def predict_one_folder_images_perbatch_return_results(folder_abspath, predicted_result_save_path, trained_model_abspath, batchSize: int = 128, isKnowClassify: int = 1):
'''对一个【已知分类的】文件夹图片一个batch一个batch的进行预测,速度更快
函数返回值如下:
true_labels 图片真实标签
predict_label_list 图片预测标签
predict_probability_list 图片预测概率
picture_name_list 图片名称(无后缀)
result_confused_matrix 混淆矩阵相关计算结果(详见函数confused_matrix)
——————————————————————————————————————————————————————————————————————————————————————
函数参数 参数含义
folder_abspath 需要预测图片所在文件夹绝对路径
predicted_result_save_path 预测分类结果保存路径
trained_model_path 训练好的模型(.h5)绝对路径
batchSize 每批次预测数量的大小,默认值为128
isKnowClassify 预测的数据真实标签是否知道
如果知道则为1(默认值),如果不知道则为0'''
index2label = {0: 'dis', 1: 'undis'}
# 获取预测文件夹下所有文件列表
imgs_test_folder_path = glob.glob(os.path.join(folder_abspath, '*.jpg'))
# 获取文件名列表
picture_name_list = [os.path.basename(a_image).split('.')[0] for a_image in imgs_test_folder_path]
# 生成预测数据slices
imgs_ds = tf.data.Dataset.from_tensor_slices(imgs_test_folder_path)
AUTOTUNE = tf.data.experimental.AUTOTUNE
# 批量读取并解析预测文件图片
imgs_ds = imgs_ds.map(load_preprocess_image_for_prediction, num_parallel_calls=AUTOTUNE)
imgs_ds = imgs_ds.batch(batch_size=batchSize)
# 加载训练好的模型,可以使用间断点训练结果也可以调用h5文件
trained_model = tf.keras.models.load_model(trained_model_abspath)
# 设置两个空列表,一个用于保存预测图片的标签、一个用于保存预测图片的预测概率
predict_label_list = []
predict_probability_list = []
# 分批次循环对所有预测图片进行分类预测
for i, imgs_batch in enumerate(imgs_ds):
total_batch = round(len(imgs_test_folder_path)/batchSize, 2)
processing_batch = round(100*i/total_batch, 2)
sys.stdout.write('\r程序运行到第{}个batch,总共需要运行{}个batch,进度为{}%......' .format(i, total_batch, processing_batch))
sys.stdout.flush()
predict_result = trained_model.predict(imgs_batch)
for per_predict_result in predict_result:
probability___dis = per_predict_result[0]
probability_undis = per_predict_result[1]
if probability___dis >= probability_undis:
predict_index = 0
predict_probability = probability___dis
predict_label = index2label.get(predict_index)
else:
predict_index = 1
predict_probability = probability_undis
predict_label = index2label.get(predict_index)
predict_label_list.append(predict_label)
predict_probability_list.append(round(predict_probability, 4))
print()
saveFileName = '预测分类结果' + get_cunrrent_datetime_mark()
if isKnowClassify == 1:
# 如果是分类标签已知的数据
true_labels = [os.path.basename(a_image).split('_')[0] for a_image in imgs_test_folder_path]
dis_num = 0
for one_label in true_labels:
if one_label == 'dis':
dis_num += 1
undis_num = len(true_labels) - dis_num
# 混淆矩阵结果计算
result_confused_matrix = predict_result_confused_matrix(true_labels, predict_label_list)
# 相关预测结果写入到excel
xls_save_path = os.path.join(predicted_result_save_path, (saveFileName + '.xls'))
_file = xlwt.Workbook(encoding='utf-8')
_sheet = _file.add_sheet('Predicted_result', cell_overwrite_ok=True)
_sheet.write(0, 0, 'True_labels')
_sheet.write(0, 1, 'Predict_labels')
_sheet.write(0, 2, 'Predict_probability')
_sheet.write(0, 3, 'File_name')
_sheet.write(0, 4, '预测结果')
for i_xls in range(len(true_labels)):
_sheet.write(i_xls + 1, 0, str(true_labels[i_xls]))
_sheet.write(i_xls + 1, 1, str(predict_label_list[i_xls]))
_sheet.write(i_xls + 1, 2, str(predict_probability_list[i_xls]))
_sheet.write(i_xls + 1, 3, str(picture_name_list[i_xls]))
if str(true_labels[i_xls]) == str(predict_label_list[i_xls]):
_sheet.write(i_xls + 1, 4, '正确')
else:
_sheet.write(i_xls + 1, 4, '错误')
_sheet_1 = _file.add_sheet('混淆矩阵', cell_overwrite_ok=True)
_sheet_1.write(0, 0, '已知分类数据总共:')
_sheet_1.write(0, 1, dis_num + undis_num)
_sheet_1.write(1, 0, '其中dis区域有:')
_sheet_1.write(1, 1, dis_num)
_sheet_1.write(2, 0, '其中undis区域有:')
_sheet_1.write(2, 1, undis_num)
_sheet_1.write(3, 0, '1、实际为 dis区域,预测为 dis区域个数有:')
_sheet_1.write(3, 1, str(result_confused_matrix[0]))
_sheet_1.write(4, 0, '2、实际为 dis区域,预测为undis区域个数有:')
_sheet_1.write(4, 1, str(result_confused_matrix[1]))
_sheet_1.write(5, 0, '3、实际为undis区域,预测为undis区域个数有:')
_sheet_1.write(5, 1, str(result_confused_matrix[3]))
_sheet_1.write(6, 0, '4、实际为undis区域,预测为 dis区域个数有:')
_sheet_1.write(6, 1, str(result_confused_matrix[2]))
_sheet_1.write(7, 0, '预测准确率为:')
_sheet_1.write(7, 1, str(round(result_confused_matrix[4], 4)))
_sheet_1.write(8, 0, '预测精确率(查准率)为:')
_sheet_1.write(8, 1, str(round(result_confused_matrix[5], 4)))
_sheet_1.write(9, 0, '召回率(查全率)【扰动样本预测为扰动样本】为:')
_sheet_1.write(9, 1, str(round(result_confused_matrix[6], 4)))
_sheet_1.write(10, 0, 'F方法值为:')
_sheet_1.write(10, 1, str(round(result_confused_matrix[7], 4)))
_file.save(xls_save_path)
# 生成混淆矩阵图片并导出
if os.path.exists(xls_save_path):
draw_confusion_matrix(xls_save_path, 'Predicted_result', 150)
else:
# 如果是:分类标签未知的数据
xls_save_path = os.path.join(predicted_result_save_path, (saveFileName + '.xls'))
_file = xlwt.Workbook(encoding='utf-8')
_sheet_2 = _file.add_sheet('预测结果', cell_overwrite_ok=True)
_sheet_2.write(0, 0, 'Predict_labels')
_sheet_2.write(0, 1, 'Predict_probability')
_sheet_2.write(0, 2, 'File_name')
for i_xls in range(len(predict_label_list)):
_sheet_2.write(i_xls + 1, 0, str(predict_label_list[i_xls]))
_sheet_2.write(i_xls + 1, 1, str(predict_probability_list[i_xls]))
_sheet_2.write(i_xls + 1, 2, str(picture_name_list[i_xls]))
_file.save(xls_save_path)
return predict_label_list, predict_probability_list, picture_name_list
四、上述函数的调用及实际图片分类预测
假设有一个文件夹是带有分类标签的,只是用于对训练模型的精度测试,那么上述函数调用如下:
该文件夹的绝对路径为:folder_abspath = r’’
此外,分类预测文件保存路径为predicted_result_save_path,训练好的模型绝对路径为trained_model_abspath
batchsize可根据实际情况自行调整。
这里是已知图片的实际分类标签,所以参数isKnowClassify=1。
调用如下函数即可:
predict_one_folder_images_perbatch_return_results(folder_abspath, predicted_result_save_path, trained_model_abspath, batchSize=128, isKnowClassify=1):
上述分类后保存一个excel分类文件,具体如下。如果是标签未知的情况,也就是isKnowClassify=0的情况,excel表格中就没有第一列和最后一列数据。
假设有一个文件夹是未知分类的,也就是图片名字中没有分类标签,需要对每个图片的分类进行预测,那么上述函数调用如下:
该文件夹的绝对路径为:folder_abspath = r’’
此外,分类预测文件保存路径为predicted_result_save_path,训练好的模型绝对路径为trained_model_abspath
这里是已知图片的实际分类标签,所以参数isKnowClassify=0。
调用如下函数即可:
predict_one_folder_images_perbatch_return_results(folder_abspath, predicted_result_save_path, trained_model_abspath, batchSize=128, isKnowClassify=0):
总结
上述为训练好的模型进行调用、预测分类的全部操作。