基于Keras从0开始构建VGG项目

引入若干功能

很多同学已经再Keras的官网上实现过VGG模型了,但如何制作训练集,测试集以及如何预测还是完全摸不到门路,本文就这些问题详细一步步去实现整个vgg项目。

项目说明

项目识别的是两个分类,分别是骷髅和猫。

项目分为训练与预测阶段分别对应vggtrain.py和pridict.py

项目有若干文件夹其中,data用于训练的图片使用。test测试图片使用,pre_pridect用于预测图片使用,data_adjust与test_adjust是用于预处理图片用的。自动化制作符合训练的的尺寸和矩阵维度。

项目训练完毕后产生model.h5存放在model文件夹中,每次训练都会被覆盖。该权重就是神经网络上的全部参数及网络本身。

构建目录结构

创建data文件夹,从网上下载,本例中前70张图片为猫咪,71-273为骷髅,图片不必限定大小格式。本例中命名顺序命名。名称上不必区分猫咪还是骷髅。(批量命名的办法和工具很多自行查找,炼丹必备)

接着创建data_adjust该文件夹用于统一图片大小和格式,这里空着即可

接着创建test文件夹,里面放入若干用于测试的猫咪和骷髅图片,本例中放入5猫咪和15张骷髅图片。

创建test_adjust该文件夹用于统一测试集图片大小和格式,这里也是空着即可 。

创建model文件夹,空着即可。

最后创建预测文件夹pre_ditect,里面放入若干待预测的图片。以顺序命名。

图片格式处理并制作训练集测试集

该部分处理所有图片使其称为统一的格式和尺寸,方便喂入模型。

创建vggtrain.py文件夹,如图所示:

有若干变量:

    datas =[]#存储训练图片格式
    datas_test=[]#存储测试集图片格式图片
    image=[]#存储格式图片
    fpaths=[]#存储文件路径
    fpaths_test=[]#存储测试文件路径

这里有个大坑,os.listdir并不是文件名循序排序的,制作标签也就是y产生不便文件名不对应,所以必须排序。

    for fname in os.listdir(data_dir):
        fpaths.append(fname)
    fpaths.sort(key=lambda x:int(x[:-4]))#排序

模型定义200*200图片作为输入。所以设计代码把所有图片转换为200*200,包括训练集,测试集与预测的图片。

image=image.resize((200, 200),Image.ANTIALIAS) #200*200的的预处理图片,ANTIALIAS可能会报错,原因是image版本,改为.LANCZOS 即可
image.save(resize_dir+"/" + fname, 'png')#存储在标准化路径下

实践发现下载的图片可能是8位的所以转换位24位并且归一化并转换位array格式,保存再datas中。

image=np.array(Image.open(fpath).convert('RGB'))/255 #打开图片转换为rgb格式,免得有的图片只有8位,除以255,因为像素是0-255,除以255可以归一化。更快的递归。
datas.append(image)

以上就完成了图片格式的统一并转为数据类型,测试集,预测图片按照上面的过程走一遍即可。

完整代码如下,都写了注释:

data_dir = "./data"#训练集素材放在这个文件夹
resize_dir= "./data_adjust"#徐哪里那几素材标准化,以满足x_train
data_test_dir="./test"#测试集素材
resize_test_dir= "./test_adjust"#素材标准化,以满足x_train
def read_data():
    datas =[]#存储训练图片格式
    datas_test=[]#存储测试集图片格式图片
    image=[]#存储格式图片
    fpaths=[]#存储文件路径
    fpaths_test=[]#存储测试文件路径
    #循序排序
    #######################################制作训练集#######################################
    # 图片规定为200*200*3的矩阵
    # 代码中可以自动转换为200*200*3矩阵
    #  训练集主要分为两个文件夹,原始素材,和标准化素材,标准化素材是指经过统一为200*200*3的图片
    #######################################################################################
    #这个主要是为了循序排序,因为os.listdir并不是文件名循序排序的,这回代制作标签也就是y产生不便,所以必须排序。
    for fname in os.listdir(data_dir):
        fpaths.append(fname)
    fpaths.sort(key=lambda x:int(x[:-4]))#排序
    # print(fpaths)
    shutil.rmtree(resize_dir)#删除练集标准化素材文件夹,以防之前的图片被保留
    os.mkdir(resize_dir)#再次创建test文件夹
    #处理data文加下的图片并循序保存在test文家中,并标准化微200*200,参数
    for fname in fpaths:
        image = Image.open(data_dir+"/"+fname)#得到训练集素材路径
        fpath = os.path.join(resize_dir, fname)#得到训练集标准化素材文件路径
        image=image.resize((200, 200),Image.ANTIALIAS) #200*200的的预处理图片,ANTIALIAS可能会报错,原因是image版本,改为.LANCZOS 即可
        image.save(resize_dir+"/" + fname, 'png')#存储在标准化路径下
        image=np.array(Image.open(fpath).convert('RGB'))/255 #打开图片转换为rgb格式,免得有的图片只有8位,除以255,因为像素是0-255,除以255可以归一化。更快的递归。
        datas.append(image)

    #######################################制作测试集#######################################
    #过程和上面一样
    #######################################################################################
    for fname in os.listdir(data_test_dir):
        fpaths_test.append(fname)
    fpaths_test.sort(key=lambda x:int(x[:-4]))#排序
    shutil.rmtree(resize_test_dir)#删除练集标准化素材文件夹,以防之前的图片被保留
    os.mkdir(resize_test_dir)#再次创建test文件夹
    #处理data文加下的图片并循序保存在test文家中,并标准化微200*200,参数
    for fname in fpaths_test:
        image = Image.open(data_test_dir+"/"+fname)
        fpath = os.path.join(resize_test_dir, fname)
        image=image.resize((200, 200),Image.ANTIALIAS) #200*200的的预处理图片
        image.save(resize_test_dir+"/" + fname, 'png')
        image = np.array(Image.open(fpath).convert('RGB'))/255 
        datas_test.append(image)

    datas=np.array(datas)#转换成np的array格式准备输入给模型作为x_train,因为kears认这个格式
    datas_test=np.array(datas_test)

    return datas,datas_test

制作训练集标签

本项目为两个分类训练集要给出矩阵哪些是猫咪哪些是骷髅。

 y_tr是一个list不可以被直接使用,需要keras.utils.to_categorical转换。

y_tr的索引号转换为y_test的行号,y_tr的0代表,在y_test行中0列设为1,而行的1值得是,在y_test行中第二列设为1.最终成为下方的样子。

[1. 0.]

 [1. 0.]

 [1. 0.]

 [0. 1.]

 [0. 1.]  

训练集y_train的行号要和x_train相同。测试集集y_test的行号要和x_test相同。

y_tr=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1]#训练集标签
y_ts=[0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]#测试集标签
print(datas[0])

训练与模型

把处理好的各项数据分别赋值给x_train,y_train ,x_test,y_test并交给模型训练即可

x_train=datas.astype(float)
y_train =keras.utils.to_categorical(y_tr,num_classes=2)
print(y_train)
x_test=datas_test.astype(float)
y_test =keras.utils.to_categorical(y_ts,num_classes=2)

模型训练

history=model.fit(x_train, y_train, batch_size=32, epochs=50)#模型的历史信息,供以后绘制模型能能图用

模型保存为h5格式

model.save("./model/model.h5", overwrite=True)#模型的权重文件,也就是模型的一切

模型阶段完整代码

x_train=datas.astype(float)
y_train =keras.utils.to_categorical(y_tr,num_classes=2)
print(y_train)
x_test=datas_test.astype(float)
y_test =keras.utils.to_categorical(y_ts,num_classes=2)
print(x_train[0])
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)
model = Sequential()
# 输入: 3 通道 100x100 像素图像 -> (100, 100, 3) 张量。
# 使用 32 个大小为 3x3 的卷积滤波器。
# model.add(Dense(32, input_shape=(103,)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))#这里的全练成是二分类,如果多分类要修改这里的2,。

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)#优化器
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy', keras.metrics.Precision(), keras.metrics.Recall()])# metrics输出模型的一些指标
#模型训练的部分调用fit
history=model.fit(x_train, y_train, batch_size=32, epochs=50)#模型的历史信息,供以后绘制模型能能图用
print(model.summary()) #模型总结

score = model.evaluate(x_test, y_test, batch_size=32)#模型评估
model.save("./model/model.h5", overwrite=True)#模型的权重文件,也就是模型的一切
print(score)

训练迭代次数等参数可以再模型中调整

预测推理

有了h5权重后就可以进行预测拉。

读取预测问价夹中的图片,过程和上面图像处理过程类似

读取模型

model = keras.models.load_model("./model/model.h5")
print("-----model loaded-----")
model.summary()#模型总结

预测推理

pre_predict = model.predict(x_test)#预测
list=pre_predict.tolist()#非必要转为list类型,只是个人习惯

对推理结果进行输出处理

while i<len(list):
    if(list[i][0]<0.5):#判断概率,通常取0.5作为临界点
        print("预测结果是骷髅,是骷髅的概率为"+str(1-pre_predict[i][0])+'\n')
    else:
        print("预测结果是猫,是猫的概率为"+str(pre_predict[i][0])+'\n')#1-掉骷髅的概率就是猫的概率,注意只是二分类可以这样写,多分类的话需要重新设计
    i+=1
        

预测文件完整代码,全是贴心注释

import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import SGD
import os
from PIL import Image
import shutil
#预测之前需要至少训练完毕一次,生成model.h5权重
#该预测支持二分类,多分类需要改最后的while里面的条件
#预测图片必须保证是200*200的rgb图片
pre_pridect="./pre_pridect"#训练文件夹
fpaths=[]#存储文件名
datas=[]#顺序存储图片
 
 #打开图片,nparry转换为十进制模式,顺序加入datas中
 #os是很好用的文件遍历库
for fname in os.listdir("./pre_pridect"):
    fpath = os.path.join(pre_pridect, fname)
    image= np.array(Image.open(fpath))/255#归一化
    datas.append(image)

#list转为np.array,keras必须要转,否则无法作为模型的输入层
datas=np.array(datas)
print(datas)
# print(datas)
#转为输入层之前最后一步,转为float
x_test=datas.astype(float)


#模型通过h5文件载入
model = keras.models.load_model("./model/model.h5")
print("-----model loaded-----")
model.summary()#模型总结

#模型预测,并返回。
pre_predict = model.predict(x_test)#预测
list=pre_predict.tolist()#非必要转为list类型,只是个人习惯

print(len(list))
i=0
#模型预测结果是一个2维数组
#该判断只适用于二分类
while i<len(list):
    if(list[i][0]<0.5):#判断概率,通常取0.5作为临界点
        print("预测结果是骷髅,是骷髅的概率为"+str(1-pre_predict[i][0])+'\n')
    else:
        print("预测结果是猫,是猫的概率为"+str(pre_predict[i][0])+'\n')#1-掉骷髅的概率就是猫的概率,注意只是二分类可以这样写,多分类的话需要重新设计
    i+=1
        




预测预览

打完收工

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值