TensorFlow實現人臉識別(4)--------對人臉樣本進行訓練,儲存人臉識別模型
阿新 • • 發佈:2018-12-29
經過前面幾章的介紹,我們以及可以得到處理好的訓練樣本影象,在本節中將對這些影象進行訓練。主要利用到的是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 後續測試時直接呼叫