当前位置: 移动技术网 > IT编程>脚本编程>Python > 基于keras训练的h5模型进行批量预测

基于keras训练的h5模型进行批量预测

2020年07月03日  | 移动技术网IT编程  | 我要评论

对单张图片进行预测

我的项目是用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)):  #循环的轮数=前面整数倍轮数+最后零头的1if 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.

本文地址:https://blog.csdn.net/weixin_44408590/article/details/107050005

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网