1、摘要
本專案將在Android上實現一種透過識別表情類別,從而給人臉戴上不同樣式臉譜的AR軟體,效果如下:
透過深度學習和Keras訓練一個人臉表情識別的卷積神經網路,然後使用TensorFlow Lite轉換為tflite檔案,部署到Android平臺。
想要實現這樣一個軟體,核心就是兩部分:
1)使用卷積神經網路訓練一個人臉表情識別模型,
2)將訓練好的模型移植到Android平臺,同時在Android實現臉譜AR效果,並結合表情識別模型的識別結果,渲染不同的臉譜樣式
本文講第一部分,如何使用Keras訓練一個人臉表情識別的卷積神經網路。
第二部分見:基於卷積神經網路的人臉表情識別應用--AR川劇變臉(二)
2、資料集處理
資料集我們使用FER2013PLUS人臉表情識別資料集,大概有35000張圖片,每張圖片是48*48解析度的灰度圖。
下圖展示7個表情類別的資料集樣本量,可以看出類別 angry、happy、sad、surprised、normal 這 5 種表情數量較多,而 disgust、fear這 2 種表情較少。
在實驗中為了防止出現過擬合現象需要進行資料集擴充,提高模型的泛化能力。資料增強是指對輸入的影像進行隨機的影像處理,比如旋轉、位移、光照強度、裁剪等,對於計算機而言,經過位移後的影像和原影像是兩幅不同的影像,但具有相同的標籤,從而擴充了已有的資料集。而透過使用大量不同的資料集來訓練網路,進一步提高深度模型的泛化能力,使得網路即不過擬合也不欠擬合,達到最佳狀態。
模型的實際使用常見是自由場景,自由場景中光照亮度的不同會影響模型的效能,新增隨機光照,同時為了擴充資料集和對非正常角度人臉的識別增加隨機旋轉、隨機聚焦和水平翻轉。下圖 展示對一張 48*48 尺寸,表情為 happy 的灰度圖進行隨機亮度、隨機旋轉、隨機聚焦和隨機水平翻轉的效果。可以看出,小型資料集藉此技術可以實現數十倍的規模擴充,而資料集規模的提升可以提升網路的泛化能力和魯棒性,提高網路在場景下的識別準確率。
在Keras中,我們需要使用資料載入器載入資料,最大化硬體利用率,幸運的是Keras已經提供了方法,我們直接使用即可:
def getDenerator(fer2013plus_path="datasets/fer2013plus", batch_size=32):
"""
我們傳遞資料集的位置和batch_size,然後函式返回用於訓練和測試的資料載入器,用於訓練時投餵資料
:param fer2013plus_path:fer2013plus資料集目錄
:param batch_size:
:return:
"""
train_datagen = ImageDataGenerator( # 定義資料增強的方式
brightness_range=(0.7, 1.3), # 隨機亮度
featurewise_center=False,
featurewise_std_normalization=False,
rotation_range=10, # 隨機旋轉
zoom_range=(0.7, 1.3), # 聚焦
horizontal_flip=True) # 水平翻轉
train_generator = train_datagen.flow_from_directory(fer2013plus_path+"/train", # 告訴Keras圖片的位置
target_size=(48, 48), # 將圖片縮放到指定大小
color_mode="grayscale", # 因為是灰度圖
batch_size=batch_size, # 一次性載入多少圖片,越大訓練越快,但是需要更多的視訊記憶體
class_mode='categorical')
test_datagen = ImageDataGenerator() # 水平翻轉
test_generator = test_datagen.flow_from_directory(fer2013plus_path+"/test",
target_size=(48, 48),
color_mode="grayscale",
batch_size=batch_size,
class_mode='categorical')
return train_generator,test_generator
3、模型設計
模型設計參考VGG網路,也就是Conv+Conv+Pool式的堆疊。
如下圖是VGG的結構,可以看出就是Conv+Conv+Pool式的堆疊,最後使用全連線層,實現1000類別的分類。
但是我們人臉表情識別資料集比較小,僅有3萬多張圖片,模型太大容易過擬合,所以以VGGNet為藍本,設計一個比較小的模型,如下圖所示,也是conv+conv+pool式,但是更小。
因為我們的表情是7中分類,所以輸出的全連線層長度是7。
在Keras中定義模型結構其實而很簡單,程式碼如下:
def getVXSlim():
model = Sequential()
# block1
model.add(Conv2D(64, (5, 5), input_shape=(48, 48, 1), activation='relu', padding='same'))
model.add(Conv2D(64, (5, 5), activation='relu', padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
# block2
model.add(Conv2D(128, (5, 5), activation='relu', padding='same'))
model.add(Conv2D(128, (5, 5), activation='relu', padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
# block3
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
# single conv
model.add(Conv2D(64, (3, 3), padding='same'))
# classifier
model.add(Flatten()) # 將多維的資料展成一列,可以理解為將影像展開成一列
model.add(Dense(7)) # 堆疊一個全連線層,長度為7
model.add(BatchNormalization())
model.add(Dense(7)) # 堆疊一個全連線層,長度為7
# config
model.add(Activation('softmax')) # 最後使用softmax啟用函式,將輸出轉換為機率
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='adam') # 定義最佳化器
return model
在上面的程式碼中使用了Conv2D、BatchNormalization、MaxPooling2D、Dense:
- Conv2D:提取特徵,將影像分解為多個特徵的組合
- BatchNormalization:將資料的分佈變換為正態分佈,再對映到其他分佈,可以加快模型的訓練速度
- MaxPooling2D:可以縮減影像的尺寸
- Dense:全連線層,用於綜合所有特徵進行判斷類別
4、訓練
其實到這裡,最重要的資料載入和模型定義就寫好了,就可以開始訓練了。訓練了100個輪次,然後開始訓練。
從圖中可以看到,訓練集精度和損失在 45epoch 左右進入緩慢最佳化階段,在 70epoch左右趨於穩定。測試集精度和損失在 45epoch 左右趨於穩定,最終測試集精度達到 83%,損失低於 0.3,取得了較好的表情識別效果。
都說深度學習是黑盒,我們來看看訓練出來的模型的視覺化效果。
在視覺化中間輸出部分,透過卷積網路的每層都會輸出結果,透過將結果視覺化可以看到輸入圖片在網路中的流動形式,在這裡展示第 3 層的 max_pooling2d、第 4 層的conv2d_2 和第 8 層的 conv2d_4 的輸出結果。在圖 中可以看出,在開始階段實際上是各種邊緣檢測器的集合,在這一階段,啟用幾乎保留了輸入影像中所有的資訊。在第二幅中,雖然仍有邊緣檢測的痕跡,但是此時更加像是對某些區域性部位的特徵檢測,隨著層數的加深,中間啟用的結果變得越來越抽象,也更加難以直觀地理解。在第三層中幾乎無法和原圖聯絡起來。所以抽象是卷積神經網路的一大能力,而這種能力也正是人類所擁有的。
我們將本文設計的模型和VGG9,以及mini_Xception進行對比:
從圖中可以看出,本文的VXSlim網路的驗證集精度最高,達到了 83%,VGG9 達到了 82%,mini_Xception 最低,只有79%
那麼本文的模型在7種表情類別上的效果如何?可以看到最好的是開心類別,正確率達到了91%!
我們把每一個類的正確識別率用曲線表示,可以看到本文設計的模型在7種類別上的正確率都是最高的,很nice!
5、效果展示
透過攝像頭進行表情識別效果展示
程式碼資源:
連結:https://pan.baidu.com/s/1Y0xWDmz_lg04PTiukoBVgQ?pwd=ozn5
提取碼:ozn5