TensorFlow实现人脸识别(4)--------对人脸样本进行训练,保存人脸识别模型

经过前面几章的介绍,我们以及可以得到处理好的训练样本图像,在本节中将对这些图像进行训练。主要利用到的是keras。

一、构建Dataset类

1.1 init 完成初始化工作

def __init__(self,path_name):
        self.train_img    = None
        self.train_labels = None
        self.valid_img    = None
        self.valid_labels = None
        self.test_img     = None
        self.test_labels  = None
        self.path_name    = path_name
        self.input_shape  = None

1.2 loadAllData(self,path_name):
加载正样本以及负样本数据 并且将数据images和labels拼接在一起

def loadAllData(self,path_name):
    positive_data_images,positive_data_labels=load_dataset(path_name,'traindata')
    negative_data_images,negative_data_labels=load_dataset(path_name,'testdata')
    #数组拼接
    images =np.concatenate((positive_data_images, negative_data_images),axis=0) 
    labels=np.concatenate((positive_data_labels, negative_data_labels),axis=0)
    return images,labels

1.3 加载数据集

def load(self,img_rows=IMAGE_SIZE,img_cols=IMAGE_SIZE,
        img_channels=3,nb_classes=2):
        images,labels = self.loadAllData(self.path_name) 
        #images为四维数组,尺寸为(图片数量总(包括test+train)*IMAGE_SIZE*IMAGE_SIZE*3)
        #随机划分训练集和验证集
        train_images,valid_images,train_labels,valid_labels = train_test_split(images,  labels,random_state = random.randint(0,100))
        _,            test_images,_,            test_labels = train_test_split(images, labels,test_size = 0.3,random_state = random.randint(0,100))

        # 当前的维度顺序如果为'th',则输入图片数据时的顺序为:channels,rows,cols,
        # 否则:rows,cols,channels
        # 这部分代码就是根据keras库要求的维度顺序重组训练数据集
        if K.image_dim_ordering() == 'th':  #theano的格式
            train_images     = train_images.reshape(train_images.shape[0], 
                                img_channels, img_rows, img_cols)
            valid_images     = valid_images.reshape(valid_images.shape[0], 
                                img_channels, img_rows, img_cols)
            test_images      = test_images.reshape( test_images.shape[0], 
                                 img_channels, img_rows, img_cols)
            self.input_shape = (img_channels, img_rows, img_cols)
        else:  # tensorflow格式
            train_images     = train_images.reshape(train_images.shape[0], 
                                img_rows, img_cols, img_channels)
            valid_images     = valid_images.reshape(valid_images.shape[0], 
                                img_rows, img_cols, img_channels)
            test_images      = test_images.reshape( test_images.shape[0],  
                                img_rows, img_cols, img_channels)
            self.input_shape = (img_rows, img_cols, img_channels)

         # 输出训练集、验证集、测试集的数量
        print(train_images.shape[0], 'train samples')
        print(valid_images.shape[0], 'valid samples')
        print(test_images.shape[0],  'test  samples')

        #根据类别数量nb_classes将类别标签进行one-hot编码使其向量化,
        #在这里我们的类别只有两种,经过转化后标签数据变为二维
        #将 1*638 变为  2*638
        train_labels = np_utils.to_categorical(train_labels,nb_classes)
        valid_labels = np_utils.to_categorical(valid_labels,nb_classes)
        test_labels  = np_utils.to_categorical(test_labels,nb_classes)

        #图像像素转为浮点
        train_images = train_images.astype('float32')
        valid_images = valid_images.astype('float32')
        test_images  = test_images.astype('float32')

        #归一化图像
        train_images /= 255
        valid_images /= 255
        test_images  /= 255

        self.train_images = train_images
        self.valid_images = valid_images
        self.test_images  = test_images
        self.train_labels = train_labels
        self.valid_labels = valid_labels
        self.test_labels  = test_labels

二、构建模型Model

2.1 验证模型

def evaluate(self,dataset):
   score = self.model.evaluate(dataset.test_images, dataset.test_labels,verbose=1)
   print('%s: %.2f%%' % (self.model.metrics_names[1], score[1] * 100))

2.2 保存模型

def save_model(self,file_path = MODEL_PATH):
        self.model.save(file_path)

2.3 加载模型

def load_model(self,file_path = MODEL_PATH):
        self.model = load_model(file_path)

2.4 建立模型

def build_model(self,dataset,nb_classes=2):
        self.model = Sequential()
        #2维卷积层   第一个卷积层包含32个卷积核,每个卷积核大小为3x3,
        #border_mode值为“same”意味着我们采用保留边界特征的方式滑窗,
        #“valid”则指定丢掉边界像素
        #input_shape的值为(64,64,3)
        self.model.add(Convolution2D(32,3,3,border_mode='same',
                            input_shape = dataset.input_shape))  
        #激活函数
        self.model.add(Activation('relu')) 
        #2维卷积层
        self.model.add(Convolution2D(32,3,3))  
        #激活函数
        self.model.add(Activation('relu'))
        #池化层  缩小输入的特征图,简化网络计算复杂度  2*2中取最大值
        self.model.add(MaxPooling2D(pool_size=(2,2)))
        #dropout层
        self.model.add(Dropout(0.25))
        #2维卷积层
        self.model.add(Convolution2D(64,3,3,border_mode='same',
                input_shape = dataset.input_shape))  
        #激活函数
        self.model.add(Activation('relu')) 
        #2维卷积层
        self.model.add(Convolution2D(64,3,3))  
        #激活函数
        self.model.add(Activation('relu'))
        #池化层
        self.model.add(MaxPooling2D(pool_size=(2,2)))
        #dropout层
        self.model.add(Dropout(0.25))
        #flatten层  全连接层要求输入的数据必须是一维的,
        #必须把输入数据“压扁”成一维后才能进入全连接层, 
        self.model.add(Flatten())
        #全连接层
        self.model.add(Dense(200))
        #激活函数
        self.model.add(Activation('relu'))
        #dropout层
        self.model.add(Dropout(0.5))
        #全连接层
        self.model.add(Dense(nb_classes))
        #分类层  这个值其实就是第j个神经元在所有神经元输出中所占的百分比。
        self.model.add(Activation('softmax'))

        #输出模型概况
        self.model.summary()

2.5 模型训练train

def train(self,dataset,batch_size = 20, nb_epoch=2,data_augmentation = True):
        # 采用SGD+momentum的优化器进行训练,首先生成一个优化器对象 
        sgd = SGD(lr=0.01,   #学习率
                  decay = 1e-6, #每次更新后学习效率的衰减值
                  momentum=0.9, #指定动量值 让优化器在一定程度上保留之前的优化方向,同时利用当前样本微调最终的优化方向,这样即能增加稳定性,提高学习速度,又在一定程度上避免了陷入局部最优陷阱
                  nesterov=True #是否采用nesterov动量方法
                  )
        # 完成实际的模型配置工作 compile之后模型就可以开始训练了
        self.model.compile( loss='categorical_crossentropy', #损失函数
                            optimizer=sgd, #优化器
                            metrics=['accuracy']
                           )
        # 不使用数据提升,所谓的提升就是从我们提供的训练数据中利用旋转、翻转、加噪声等方法创造新的训练数据,有意识的提升训练数据规模,增加模型训练量
        if not data_augmentation:
            self.model.fit(    #即可开始模型训练
                           dataset.train_images,
                           dataset.train_labels,
                           batch_size = batch_size, #每次迭代训练样本的数量
                           nb_epoch = nb_epoch, #训练轮次  使用训练集全部样本训练一次为一个训练轮次
                           validation_data = (dataset.valid_images,dataset.valid_labels),
                           shuffle = True  #是否随机打乱数据集
                           )
        else:
            #定义数据生成器用于数据提升,其返回一个生成器对象datagen,datagen每被调用一次其生成一组数据(顺序生成),节省内存,其实就是python的数据生成器
            datagen = ImageDataGenerator(
                featurewise_center=False,  # 是否使输入数据去中心化(均值为0),
                samplewise_center=False,  # 是否使输入数据的每个样本均值为0
                featurewise_std_normalization=False,  # 是否数据标准化(输入数据除以数据集的标准差)
                samplewise_std_normalization=False,  # 是否将每个样本数据除以自身的标准差
                zca_whitening=False,  # 是否对输入数据施以ZCA白化
                rotation_range=20,  # 数据提升时图片随机转动的角度(范围为0~180)
                width_shift_range=0.2,  # 数据提升时图片水平偏移的幅度(单位为图片宽度的占比,0~1之间的浮点数)
                height_shift_range=0.2,  # 同上,只不过这里是垂直
                horizontal_flip=True,  # 是否进行随机水平翻转
                vertical_flip=False  # 是否进行随机垂直翻转
            )
            # 计算整个训练样本集的数量以用于特征值归一化、ZCA白化等处理
            datagen.fit(dataset.train_images)
            # 利用生成器开始训练模型
            self.model.fit_generator(datagen.flow(dataset.train_images,dataset.train_labels,batch_size = batch_size),
                                     samples_per_epoch = dataset.train_images.shape[0],
                                     nb_epoch = nb_epoch,
                                     validation_data = (dataset.valid_images,dataset.valid_labels)
                                     )

2.6 计算预测的概率

def face_predict(self,image):
        if K.image_dim_ordering() == 'th' and image.shape != (1, 3, IMAGE_SIZE, IMAGE_SIZE):
            image = resize_image(image)  # 尺寸必须与训练集一致都应该是IMAGE_SIZE x IMAGE_SIZE
            image = image.reshape((1, 3, IMAGE_SIZE, IMAGE_SIZE))  # 与模型训练不同,这次只是针对1张图片进行预测
        elif K.image_dim_ordering() == 'tf' and image.shape != (1, IMAGE_SIZE, IMAGE_SIZE, 3):
            image = resize_image(image)
            image = image.reshape((1, IMAGE_SIZE, IMAGE_SIZE, 3))

        image = image.astype('float32')
        image  /=255
        # 给出输入属于各个类别的概率,我们是二值类别,则该函数会给出输入图像属于0和1的概率各为多少
        #result = self.model.predict_proba(image)
        #print('result:', result)
        #预测
        result = self.model.predict_classes(image)
        return result[0]

三、主运行程序
3.1 获取当前路径

path_name = os.getcwd() #获得当前路径

3.2 获取数据集

dataset = Dataset(path_name) #获取数据集

3.3 加载数据集

dataset.load()

3.4 构建模型

 model = Model()
 model.build_model(dataset)

3.5 训练模型 保存模型

model.train(dataset)
    model.save_model(file_path = './face.model.h5')

经过上述步骤 可以将其训练好的模型保存起来 face.model.h5 后续测试时直接调用

源码下载:http://download.csdn.net/download/yunge812/10270013
参考博文:http://blog.csdn.net/wearge/article/category/7092833
http://blog.csdn.net/xvshu/article/details/78863430

猜你喜欢

转载自blog.csdn.net/yunge812/article/details/79447179