对单张图片进行预测
我的项目是用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_x
2、测试函数
(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+=1
3、主函数
主函数使用定义的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:
pass
4、 运行结果
预测时:
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.