选择了猫狗分类这个不是很困难的例子来做CNN的demo,数据可从kaggle下载:
kaggle Dogs vs Cats
猫狗数据各有12500张训练数据即25000张,每张图片前三个字母为cat或者dog,可以此作为分类。测试共有12500张,测试数据没有进行分类。
先对数据进行预处理操作:
import os
import shutil
file_names = os.listdir('./train/')
train_cats = filter(lambda x:x[:3]=='cat',file_names)
train_dogs = filter(lambda x:x[:3]=='dog',file_names)
def createDir(path):
if not os.path.exists(path):
try:
os.makedirs(path)
except:
print("创建文件夹失败")
exit(1)
createDir('./train_data')
createDir('./train_data/cats')
createDir('./train_data/dogs')
cats = list(train_cats)
dogs = list(train_dogs)
for cat in cats[:5000]:
shutil.move('./train/'+cat,'./train_data/cats/')
print(' 猫猫操作成功!')
for dog in dogs[:5000]:
shutil.move('./train/'+dog,'./train_data/dogs/')
print(' 狗狗操作成功!')
这时候拥有了分好类的两组图,各5000张存到了对应的文件夹里。
进行训练
from keras.preprocessing.image import ImageDataGenerator
train_pic_gen = ImageDataGenerator(rescale=1./255,
fill_mode='nearest',
horizontal_flip=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.5,
shear_range=0.5,
zoom_range=0.2)
test_pic_gen = ImageDataGenerator(rescale=1./255)
train_flow = train_pic_gen.flow_from_directory(train_dir,target_size=(128,128),batch_size = 32,class_mode ='binary' )
test_flow = test_pic_gen.flow_from_directory(test_dir,(128,128),batch_size=32,class_mode='binary')
print(train_flow.class_indices)
建立循环神经网络,为常规的CNN模型,并将模型保存下来
from keras.models import Sequential
from keras.layers import Conv2D,Dense,MaxPooling2D,Flatten,Dropout,BatchNormalization
model = Sequential()
model.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=(128,128,3),activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(filters=164,kernel_size=(3,3),activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Flatten())
model.add(Dense(100,activation='relu'))
model.add(Dense(1,activation='sigmoid'))
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])
his = model.fit_generator(train_flow,steps_per_epoch=100,epochs=20,validation_data=test_flow,validation_steps=100)
model.save('./model_1.h5')
训练结果:
import matplotlib.pyplot as plt
plt.plot(his.history['acc'])
plt.plot(his.history['val_acc'])
plt.title('model_accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
plt.plot(his.history['loss'])
plt.plot(his.history['val_loss'])
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
#plt.show()
可以看出模型在训练集和测试集上的预测准确率达到了70%,但是我还是希望他能更准确一点,下面开始调参,各种参数调一调试一试吧。
将图片大小调为64*64后:
加入新的一层卷积层,并调大了训练的步长:
最后用上面这个模型再fit一次整个数据集,进行五十步,得到下面结果:
利用这个模型进行预测。测试图为这只可爱猫猫:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import cv2
这里有两种方式读图,都是读为np.array格式,但是细节上有所区别。这里用cv2打印mlt读的图就能看到区别
pre_x = cv2.imread('./cat.jpg')
pre_x1 = mpimg.imread('./cat.jpg')
cv2.imshow('show',pre_x1)
cv2.waitKey()
plt.imshow(pre_x)
cv2中的色彩排列是(b,g,r),而matplotlib库中的排列方式是(r,g,b),具体可以参考:
Python中cv2库和matplotlib库色彩空间排布不一致
所以在数据处理时,如果使用cv2读的图则需要将色彩排布空间修改一下,下面是处理部分:
pre_x = cv2.resize(pre_x,(128,128))#resize成训练时的大小
pre_x = cv2.cvtColor(pre_x_fi, cv2.COLOR_BGR2RGB)#修改色彩排布
pre_x = pre_x/255
pre_x = np.expand_dims(pre_x,axis=0)#手动添加一维,让网络能读取,原先的shape是(128,128,3),变成(1,128,128,3)
预测:
model_3 = load_model('./model_3.h5')
pre_y = model_3.predict(pre_x_fi)
print(pre_y)
结果为:
[[0.38590088]]
可用如下的语句查看原先的分类:
print(train_flow.class_indices)
{'cats': 0, 'dogs': 1}
结果值<0.5,所以为猫,预测成功。
目前只学了CNN的一点知识,这个demo完成度还可以,后面会学习机器学习的更多东西,有问题一起交流讨论。