1、预处理图片数据集
(1)增强数据集
如果图片数量少的话,可以通过keras.preprocessing.image中的ImageDataGenerator函数进行数据增强,即通过旋转,翻转等操作增加图片的数量。(训练集和测试集都要)
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from PIL import Image
import os
datagen = ImageDataGenerator(
rotation_range=0.2,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
def generator(filepath):
images = os.listdir(filepath) # 把该路径下所有图片都读取
for name in images:
#读取每一张图片,并转化成矩阵
img=Image.open('picture/test/horse/'+name)
x=img_to_array(img)
x=x.reshape((1,)+x.shape)
i = 0
for batch in datagen.flow(x,
batch_size=1,
save_to_dir='test_augmentation/horse',#生成后的图像保存路径
save_prefix='3', #生成图片名称的前缀(用于作为数据的标签)
save_format='jpg'): #图片保存的格式
i += 1
if i > 20: #这个20指出要扩增多少个数据
break # otherwise the generator would loop indefinitely
generator('picture/test/horse')
(2)将图片裁剪成统一的形状,以便于输入到神经网络中
os.listdir(’ 文件夹名称’)函数用于遍历文件夹中文件的名称
def convertjpg(jpgfile,outdir,width=100,height=100):
#导入图片名称为jpgfile,输出到outdir文件中
img=Image.open('test_augmentation/'+jpgfile)
try:
#将图片resize成100*100的大小
new_jpg=img.resize((width,height),Image.BILINEAR)
#保存到路径outdir下
new_jpg.save(os.path.join(outdir,os.path.basename(jpgfile)))
except Exception as e:
print(e)
for jpgfile in os.listdir('test_augmentation'):
#遍历文件中的文件名称
print(jpgfile)
convertjpg(jpgfile,'test1')
(3)改变图片的名称
通过os.rename(‘旧名字’,‘新名字’),将图片的名字改成具有标签性质的名字,方便之后进行标签的提取。
def rename(filepath,kind):
#kind为分类后的类别
flag=True
images=os.listdir(filepath) #把该路径下所有图片都读取
for name in images:
if flag:
os.chdir(filepath)
flag=False
#用后面参数的名字代替原来的名字
os.rename(name,kind+'_'+name+'.jpg')
rename('picture/train/dia','0')
将预处理后的所有图片都存入train和test文件夹中,数据集准备完毕。
2、神经网络训练
(1)数据处理
首先需要将图片转化成数据的形式以此存入x_train中,这样才能输入到神经网络中。
再通过图片的名称提取出标签,存入y_train中,同理完成x_test和y_test
#将训练集图片转换成数组
image1=os.listdir('train_augmentation') #读取文件夹中所有的图片
def read_image1(filename):
img=Image.open('train_augmentation/'+filename).convert('RGB')
#把读取出来的图片转化成numpy高维数组
return np.array(img)
x_train=[]
for i in image1:
x_train.append(read_image1(i))
#根据文件名字提取标签
y_train=[]
for filename in image1:
y_train.append(int(filename.split('_')[0])) #把文件名按下划线分割并取第一个元素
y_train=np.array(y_train) #将标签转化为numpy类型的数组
#-----------------------------------------------------------------------------------------------
# 将测试图片转换成数组
image1 = os.listdir('test_augmentation') # 读取文件夹中所有的图片
def read_image1(filename):
img = Image.open('test_augmentation/' + filename).convert('RGB')
# 把读取出来的图片转化成numpy高维数组
return np.array(img)
x_test = []
for i in image1:
x_test.append(read_image1(i))
# 根据文件名字提取标签
y_test = []
for filename in image1:
y_test.append(int(filename.split('_')[0])) # 把文件名按下划线分割并取第一个元素
y_test = np.array(y_test) # 将标签转化为numpy类型的数组
(2)对标签编码并归一化
keras中对标签的编码有特定的要求,比如四分类问题,需要输出第一个分类,则应该输出1,0,0,0;第二个分类则输出0,1,0,0
from keras.utils import np_utils
y_train=np_utils.to_categorical(y_train)
y_test=np_utils.to_categorical(y_test)
(3)对图片像素进行归一化
因为图片的像素数据是在0~255之间的,数据比较大,为了提高特征提取的精度,并且加快收敛,需要将数据进行归一化,即压缩到0到1之间。
归一化 将像素0~255转换成0~1,提高特征提取精度,加快收敛
x_train=np.array(x_train) #需要将图片数据转化成numpy数组格式,不能是列表形式
x_test=np.array(x_test)
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
x_train/=255
x_test/=255
(4)建立模型
#建立模型
model=Sequential()
model.add(Conv2D(32,(3,3),activation='relu',input_shape=(100,100,3)))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(512,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4,activation='softmax')) #最后一层决定分多少类,分类用
#定义优化器
sgd=SGD(lr=0.01,decay=1e-6,momentum=0.9,nesterov=True)
model.compile(loss='categorical_crossentropy',optimizer=sgd,metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=64,epochs=50) #一次处理batch_size张图片,一共训练50次
#保存权重,预测时只需要加载权重文件就能预测
model.save_weights('picture.h5',overwrite=True)
#用测试集评价
score=model.evaluate(x_test,y_test,batch_size=10)
print(score)
训练结束后,将权重保存在picture.h5中,在之后只需要加载权重就可以预测图片
3、预测
首先和上面的数据预处理一样,需要对图片进行裁剪,并转化成多为数据的形式,再进行归一化操作。
然后再给出训练时的模型框架(这个必须要有,且要与训练的框架一样),再通过model.load_weights(‘picture.h5’)加载模型权重。
最后通过model.predict_classes进行预测
import os
from PIL import Image
import numpy as np
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation,Flatten
from keras.optimizers import SGD,RMSprop,Adam
from keras.layers import Conv2D,MaxPool2D
def prepicture(picname):
#读取图片,并resize成(100,100)
img=Image.open('predict/'+picname)
new_img=img.resize((100,100),Image.BILINEAR)
new_img.save(os.path.join('predict/',os.path.basename(picname)))
def read_image2(filename):
#将图片转化成多维数组
img=Image.open('predict/'+filename).convert('RGB')
return np.array(img)
prepicture('bus.jpg')
x_test=[]
x_test.append(read_image2('bus.jpg'))
x_test=np.array(x_test)
x_test=x_test.astype('float32')
x_test/=255
#在预测的时候必须给出模型
model=Sequential()
model.add(Conv2D(32,(3,3),activation='relu',input_shape=(100,100,3)))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(256,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4,activation='softmax')) #最后一层决定分多少类,分类用
model.load_weights('picture.h5')
classes=model.predict_classes(x_test)[0]
print(classes)
下面给出训练的全部代码:
import os
from PIL import Image
import numpy as np
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation,Flatten
from keras.optimizers import SGD,RMSprop,Adam
from keras.layers import Conv2D,MaxPool2D
#---------------------------------------------------------------------------------------------
#将训练集图片转换成数组
image1=os.listdir('train_augmentation') #读取文件夹中所有的图片
def read_image1(filename):
img=Image.open('train_augmentation/'+filename).convert('RGB')
#把读取出来的图片转化成numpy高维数组
return np.array(img)
x_train=[]
for i in image1:
x_train.append(read_image1(i))
#根据文件名字提取标签
y_train=[]
for filename in image1:
y_train.append(int(filename.split('_')[0])) #把文件名按下划线分割并取第一个元素
y_train=np.array(y_train) #将标签转化为numpy类型的数组
#-----------------------------------------------------------------------------------------------
# 将测试图片转换成数组
image1 = os.listdir('test_augmentation') # 读取文件夹中所有的图片
def read_image1(filename):
img = Image.open('test_augmentation/' + filename).convert('RGB')
# 把读取出来的图片转化成numpy高维数组
return np.array(img)
x_test = []
for i in image1:
x_test.append(read_image1(i))
# 根据文件名字提取标签
y_test = []
for filename in image1:
y_test.append(int(filename.split('_')[0])) # 把文件名按下划线分割并取第一个元素
y_test = np.array(y_test) # 将标签转化为numpy类型的数组
#----------------------------------------------------------------------------------------
#对标签进行keras中特定方式的编码
y_train=np_utils.to_categorical(y_train)
y_test=np_utils.to_categorical(y_test)
#归一化 将像素0~255转换成0~1,提高特征提取精度,加快收敛
x_train=np.array(x_train) #需要将图片数据转化成numpy数组格式,不能是列表形式
x_test=np.array(x_test)
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
x_train/=255
x_test/=255
#-----------------------------------------------------------------------------------------
#建立模型
model=Sequential()
model.add(Conv2D(32,(3,3),activation='relu',input_shape=(100,100,3)))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(512,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4,activation='softmax')) #最后一层决定分多少类,分类用
#定义优化器
sgd=SGD(lr=0.01,decay=1e-6,momentum=0.9,nesterov=True)
model.compile(loss='categorical_crossentropy',optimizer=sgd,metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=64,epochs=50) #一次处理batch_size张图片,一共训练50次
#保存权重,预测时只需要加载权重文件就能预测
model.save_weights('picture.h5',overwrite=True)
#用测试集评价
score=model.evaluate(x_test,y_test,batch_size=10)
print(score)
ps:
如果训练数据时出现了:
1、损失函数不下降
2、正确率很低
3、学习效果不好
原因:
1、数据集太小(可以增强数据)
2、神经网络模型不好,无法提取更深的特征
3、图片预处理不够,可以通过cv2进行图像处理