1. 程式人生 > >TensorFlow實現人臉識別(4)--------對人臉樣本進行訓練,儲存人臉識別模型

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 後續測試時直接呼叫