我的项目是用keras分出4类有形成分图片,分别为CAOT(草酸钙),NSE(上皮细胞),RBC(红细胞),WBC(白细胞),所有图像都是150*150的三通道图片,对单张图像进行预测的原理是将训练好的h5模型用方法load_model加载出来,然后将图片进行一些预处理步骤,最后用model中的predict方法进行预测,代码如下:
from keras.models import load_model from keras.preprocessing import image import numpy as np #加载模型 model = load_model("D:/keras/模型/cell.h5") model.summary() #图像预处理 file_path='D:/1_49.bmp' img = image.load_img(file_path, target_size=(150, 150)) img_tensor = image.img_to_array(img) img_tensor=np.expand_dims(img_tensor,axis=0) img_tensor/=255. print('该图像的尺寸为:',img_tensor.shape) #模型预测 prediction=model.predict(img_tensor) %返回该图片属于每一类的概率值列表 print('每一类别的概率值:',prediction) pre_y=np.argmax(prediction) print("该图片为第%d类"%pre_y)运行结果:
该图像的尺寸为: (1, 150, 150, 3) 每一类别的概率值: [[8.8744347e-14 1.0000000e+00 2.1419935e-13 1.8285983e-08]] 该图片为第1类其中,0类代表CAOT,1类代表NSE,2类代表RBC,3类代表WBC
由于数据集中图片数量较多,所以用一些简单的for循环来进行批量测试,我的项目中需要识别四种有形成分的数量分别为:CAOT(草酸钙)1087张,NSE(上皮细胞)940张,RBC(红细胞)10687张,WBC(白细胞)6747张,一共19461张。代码如下:
1、图像预处理
该函数使用了博客中的函数:利用keras加载训练好的.H5文件,并预测图片.
import matplotlib matplotlib.use('Agg') import os from keras.models import load_model import numpy as np import cv2 def get_inputs(src=[]): #预处理函数 pre_x = [] for s in src: input = cv2.imread(s) input = cv2.resize(input, (150, 150)) input = cv2.cvtColor(input, cv2.COLOR_BGR2RGB) pre_x.append(input) # input一张图片 pre_x = np.array(pre_x) / 255.0 return pre_x2、测试函数
(1)首先加载模型,设置要预测图片集的路径
model = load_model("D:/keras/模型/cell.h5") #加载模型h5文件 model.summary() predict_dir = 'D:/validation222/' test11 = os.listdir(predict_dir) #test11是一个列表,以字符串形式包含了四类的标签 images = [] #新建一个列表保存预测图片的地址 #设置计数变量的初始值,仅因为本项目需要而设计: c_c=0;c_n=0;c_r=0;c_w=0;n_c=0;n_n=0;n_r=0;n_w=0;r_c=0;r_n=0;r_r=0;r_w=0;w_c=0;w_n=0;w_r=0;w_w=0(2)定义测试函数: 在测试函数中,第一个for循环借鉴了博客 :keras中对多张输入图片进行预测并返回预测结果.中的一部分
#begin为测试开始处的图片索引值,boost为一次测试多少张图片,LABEL为输入的真实类别 def test(begin,boost,LABEL): #计数变量设为全局变量,仅本项目计数需要而设置 global c_c,c_n,c_r,c_w,n_c,n_n,n_r,n_w,r_c,r_n,r_r,r_w,w_c,w_n,w_r,w_w boost=int(boost);begin=int(begin);LABEL=int(LABEL) for testpath in test11: #得到每一张图片的路径 for fn in os.listdir(os.path.join(predict_dir, testpath)): if fn.endswith('bmp'): fd = os.path.join(predict_dir, testpath, fn) images.append(fd) #fd即为每张图片的路径 for i in range(boost): pre_x = get_inputs(images[begin:begin+boost]) #images为保存了每张图片路径的列表 pre_y = model.predict(pre_x) pre_y=np.argmax(pre_y[i]) #取预测列表中的最大值作为预测标签 print(pre_y) #以下均为计算每一类别的精准率和召回率而设置: if LABEL==0: if pre_y ==0: c_c +=1 elif pre_y ==1: c_n +=1 elif pre_y ==2: c_r+=1 elif pre_y ==3: c_w+=1 elif LABEL==1: if pre_y ==0: n_c +=1 elif pre_y ==1: n_n +=1 elif pre_y ==2: n_r+=1 elif pre_y ==3: n_w+=1 elif LABEL==2: if pre_y ==0: r_c +=1 elif pre_y ==1: r_n +=1 elif pre_y ==2: r_r+=1 elif pre_y ==3: r_w+=1 elif LABEL==3: if pre_y ==0: w_c +=1 elif pre_y ==1: w_n +=1 elif pre_y ==2: w_r+=1 elif pre_y ==3: w_w+=13、主函数
主函数使用定义的test函数进行预测,并用for循环来遍历每一个类别
首先,刚才定义的test函数需要传入三个变量,begin是测试的起始图片索引值,boost是每次测试的图片数量,LABEL是测试图片的真实标签。而在本项目中,boost在本项目中取值均为10,而由于每一类别的图片总数不一定是10的整数倍数,所以需要将每一类别的图像总数对boost进行取余操作,即单独对图像总数的零头数目进行test函数预测。
例如:CAOT这一类别包含了1087张图片,从第0张开始预测,每次预测10张,一共要进行109轮预测才能全部预测完,那么进行到108轮预测时,最后一轮只剩了7张图片,若仍以10张的boost来进行预测,那么将会取出NSE这一类别中的前三张图片来使得最后一轮测试满足10张,所以这样程序会认为这三张图片是CAOT误判为了NSE,导致预测不准。解决: 将CAOT的总数1087张对boost(也就是10)进行取余运算,将余数赋值给变量x,这样便可以让最后一轮的预测采用以x为boost值传入test函数中进行预测,而前面108轮预测仍以10作为boost值进行预测。
代码如下:
if __name__ == '__main__': sum_caot=1087;sum_nse=940;sum_rbc=10687;sum_wbc=6747 # 每一类别的图像总数 i=10;s=0;L=int(test11[0]) #设置传入test函数的三个变量初始值,其中test11=['0','1','2','3'] a=sum_caot%i;b=sum_nse%i;c=sum_rbc%i;d=sum_wbc%i #每一类别对boost值即变量i进行取余 #对CAOT进行测试: for w in range(int((sum_caot-a)/i+1)): #循环的轮数=前面整数倍轮数+最后零头的1轮 if s+i<=sum_caot-a: #前面整数倍的轮数,对caot来说就是前面的108轮预测 test(s,i,L) s+=i #将test的起始位置定位到下一轮预测的起始位置 print('已测CAOT数目:',s) elif s<=sum_caot: #最后零头的那1轮,对caot来说就是最后那包含7张图片的一轮 test(s,a,L) s+=a print('已测CAOT数目:',s) #对NSE进行测试: for w in range(int((sum_nse-b)/i+1)): if s+i-sum_caot<=sum_nse-b: L=int(test11[1]) #此时对NSE进行测试,真实标签变为1 test(s,i,L) s+=i print('已测NSE数目:',s-sum_caot) elif s-sum_caot<=sum_nse: test(s,b,L) s+=b print('已测NSE数目:',s-sum_caot) #对RBC进行测试: for w in range(int((sum_rbc-c)/i+1)): if s+i-sum_caot-sum_nse<=sum_rbc-c: L=int(test11[2]) test(s,i,L) s+=i print('已测RBC数目:',s-sum_caot-sum_nse) elif s-sum_caot-sum_nse<=sum_rbc: test(s,c,L) s+=c print('已测RBC数目:',s-sum_caot-sum_nse) #对WBC进行测试: for w in range(int((sum_wbc-d)/i+1)): if s+i-sum_caot-sum_nse-sum_rbc<=sum_wbc-d: L=int(test11[3]) test(s,i,L) s+=i print('已测WBC数目:',s-sum_caot-sum_nse-sum_rbc) elif s-sum_caot-sum_nse-sum_rbc<=sum_wbc: test(s,d,L) s+=d print('已测WBC数目:',s-sum_caot-sum_nse-sum_rbc)然后就是主函数中的统计总数和计算精准率和召回率的部分了。
#最终统计部分,计算精准率和召回率: CAOT=c_c+n_c+r_c+w_c NSE=c_n+n_n+r_n+w_n RBC=c_r+n_r+r_r+w_r WBC=c_w+n_w+r_w+w_w ALL=CAOT+NSE+RBC+WBC print('CAOT预测总数:',CAOT); print('NSE预测总数:',NSE) print('RBC预测总数:',RBC) print('WBC预测总数:',WBC) print('已经检测细胞数:',ALL) #某一类别判为其他类别的总数: c_o=c_n+c_r+c_w n_o=n_c+n_r+n_w r_o=r_c+r_n+r_w w_o=w_c+w_n+w_r #其他类别判为某一类别的总数: o_c=n_c+r_c+w_c o_n=c_n+r_n+w_n o_r=c_r+n_r+w_r o_w=c_w+n_w+r_w try: pre_c=c_c/(c_c+o_c) pre_n=n_n/(n_n+o_n) pre_r=r_r/(r_r+o_r) pre_w=w_w/(w_w+o_w) pre_c = str(pre_c*100) + '%' pre_n = str(pre_n*100) + '%' pre_r = str(pre_r*100) + '%' pre_w = str(pre_w*100) + '%' recall_c=c_c/(c_c+c_o) recall_n=n_n/(n_n+n_o) recall_r=r_r/(r_r+r_o) recall_w=w_w/(w_w+w_o) recall_c = str(recall_c*100) + '%' recall_n = str(recall_n*100) + '%' recall_r = str(recall_r*100) + '%' recall_w = str(recall_w*100) + '%' print("CAOT精准率:",pre_c) print("NSE精准率:",pre_n) print("RBC精准率:",pre_r) print("WBC精准率:",pre_w) print("CAOT召回率:",recall_c) print("NSE召回率:",recall_n) print("RBC召回率:",recall_r) print("WBC召回率:",recall_w) except: pass4、 运行结果 预测时:
0 0 0 2 0 2 0 0 0 0 已测CAOT数目: 1080 0 0 2 0 2 0 2 已测CAOT数目: 1087可以看到,预测CAOT时,最后一轮预测只有7张,而预测CAOT时前面的108轮均有10张
1、我是一个刚开始学习机器学习的小白,很多东西都不太懂,这也是第一次写博客,只是网上查了很久似乎没有我可以使用的批量预测程序,所以就写个博客记录一下,有什么地方不对的欢迎大佬指正!
2、速度问题: 其实我一开始使用的是tensorflow环境进行训练和预测,采用的预测方法是加载一次模型仅预测一张图片,然后将这个过程一直循环,直至数据集中所有图片循环完为止,这样预测速度极慢。
而现在使用keras中的predict方法进行预测,虽然使得预测速度提升了很多,但是也就是20帧左右的状态,速度也不算快,而一轮预测的图片数量设置较大时,也就是test函数中的boost取值较大时,例如boost=60,则预测速度将会变慢很多;且网络结构较复杂时,预测速度也会有所影响,目前还是不知道如何进行改进。
放在了GitHub上:链接: keras-batch-test.