CNN人脸识别(误)低配版:辛普森一家
看动画也不忘机器学习✌( •̀ ω •́ )y:
这个项目在Keras(后端为Tensorflow)上实现用神经网络根据动画片截图对辛普森一家的成员进行分类,使用的是目前最复杂和艰深的神经网络之一:卷积神经网络(Convolutional Neural Network,CNN)。
数据集为11个辛普森家族的成员的动画片截图,存放在11个文件夹中,每个成员有大约1000张图片。
这些图片有不一样的尺寸,在进过归一化后和标签一起输入神经网络进行训练
由于这次图像识别训练直接用的图片,因此该程序实际上可以用来做很多事情(验证码识别,智能交通领域的机器视觉,行人和车辆识别),只需更换文件夹路径,指向新的数据集即可。
直接上代码:
导入依赖库:
from PIL import Image import numpy as np import os import glob import re import keras from keras.optimizers import SGD, Adam from keras.models import Sequential from keras.models import load_model from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.utils import np_utils from keras import backend as K
*定义函数:从数据集中导入图片,归一化后再转化为特征矩阵:
每个文件夹中取前100张图片的数据放到测试集,剩余的样本全都作为训练集。*
def read_img(location): x_train = [] y_train = [] x_test = [] y_test = [] label_name = [] dirs = os.listdir(location) label = 0 count = 0 for i in dirs: #loop all directory print(i) n = 0 label_name.append(i) #save folder name in var label_name x_s = 200 y_s = 200 for pic in glob.glob(location+'\\'+i+'\*.jpg'): im = Image.open(pic) #open data im = im.resize((x_s, y_s), Image.ANTIALIAS) im = np.array(im) #store im as numpy array if(im.shape[0]==200 and im.shape[1]==200): r = im[:,:,0] g = im[:,:,1] b = im[:,:,2] if(n<100): x_test.append([r,g,b]) #save in x_test y_test.append([label]) #save in y_test else: #remaining data set as training data x_train.append([r,g,b]) #save in x_train y_train.append([label]) #save in y_train n = n + 1 count = count + 1 label = label + 1 #increment label print(label_name) print(dirs) return np.array(x_train),np.array(y_train),np.array(x_test),np.array(y_test)
将图片经过归一化处理,变为200p200p的尺寸:*
原图:
归一化的图片:
通过定义的函数生成训练数据、训练标签、测试数据、测试标签:
path='E:\\JLD\\desktop\\the-simpsons-characters-dataset\\simpsons_dataset' img_rows = 200 #num of image height img_cols = 200 #num of image width num_class = 11 #num of classes/labels x_train,y_train,x_test,y_test = read_img(path)
输出的结果:完成对11个文件夹的遍历,并输出训练标签向量和测试标签向量:
对训练数据和测试数据的值做线性变化,提高机器学习的速率,并将标签转化为向量,以便用交叉熵计算loss值:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 3) x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 3) input_shape = (img_rows, img_cols, 3) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 y_train = keras.utils.to_categorical(y_train, num_class) y_test = keras.utils.to_categorical(y_test, num_class)
输出训练训练特征矩阵、训练标签向量、测试特征矩阵、测试标签向量的维度:
print(x_train.shape) print(y_train.shape) print(x_test.shape) print(y_test.shape)
运行结果:
定义CNN神经网络模型:
model = Sequential() model.add(Conv2D(64, kernel_size=(3, 3),activation='relu',input_shape=input_shape)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(32, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(32, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(num_class, activation='softmax'))
编译模型:用交叉熵作为损失值,随机梯度下降作为优化器,预测的准确率用以定义模型的好坏。
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True), metrics=['accuracy'])
训一次模型并保存:模型一个批次处理64个样本,迭代1次,用测试集数据做验证。
model.fit(x_train, y_train, batch_size=64, epochs=1, verbose=1, validation_data=(x_test, y_test)) model.save('Simpson.h5')
循环进行模型训练,每一次循环迭代一次训练,保存并读取模型,循环十次,这样写是因为避免显存溢出导致之前所有训练结果丢失。该语句可重复运行。机器学习,俗称“炼丹”:
for i in range(0,10): print('The '+str(i)+' th Iteration') model=load_model('Simpson.h5') model.fit(x_train, y_train, batch_size=64, epochs=1, verbose=1, validation_data=(x_test, y_test)) model.save('Simpson.h5') K.clear_session()
运行结果:该模型在测试集上最终达到了99.09%的准确率。
若要用该模型进行识别应用,只需调用model.predict()函数就行。