2013年的時候,Kaggle曾組織過一次人臉表情識別大賽,參賽者要搭建一個模型,識別7種人類面部表情。雖然好幾年過去了,期間也陸續出現了一些研究成果,但這依然是個頗有趣的課題。在本文,我(做者Sefik Serengil——譯者注)會展現如何用Keras識別人物面部表情。python
咱們的訓練集和測試集仍是使用 Kaggle 當年比賽用的數據集 Fec2013,點擊這裏能夠獲取。 該數據集壓縮後大小爲 92 M,未壓縮版本大小爲 295 M。數據集中包含 2 萬 8 千張訓練照片和 3 萬張測試照片。每一張照片都存儲爲 48 X 48 像素。純數據集包含圖像像素(48 X 48 = 2304 個值),每張圖像中人臉的表情,和使用類型(用做訓練或測試)。git
把數據集下載到本地數據文件夾後,用以下代碼讀取數據集內容:github
with open("/data/fer2013.csv") as f:
content = f.readlines()
lines = np.array(content)
num_of_instances = lines.size
print("number of instances: ",num_of_instances)
複製代碼
最近幾年,深度學習技術在計算機視覺研究佔據了主要地位,即使是學術性的計算機視覺大會也緊密轉爲深度學習研討會。在這裏,咱們會使用深度學習中的卷積神經網絡完成本次任務。而後咱們會利用 TensorFlow 的後端,使用 Keras 構建卷積神經網絡。express
咱們已經將數據集下載到了本地,如今能夠把訓練集和測試集存儲爲專用變量了。後端
x_train, y_train, x_test, y_test = [], [], [], []
for i in range(1,num_of_instances):
emotion, img, usage = lines[i].split(",")
val = img.split(" ")
pixels = np.array(val, 'float32')
emotion = keras.utils.to_categorical(emotion, num_classes)
if 'Training' in usage:
y_train.append(emotion)
x_train.append(pixels)
elif 'PublicTest' in usage:
y_test.append(emotion)
x_test.append(pixels)
複製代碼
而後構造卷積神經網絡架構:數組
model = Sequential()
#第一個卷積層
model.add(Conv2D(64, (5, 5), activation='relu', input_shape=(48,48,1)))
model.add(MaxPooling2D(pool_size=(5,5), strides=(2, 2)))
#第二個卷積層
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(AveragePooling2D(pool_size=(3,3), strides=(2, 2)))
#第三個卷積層
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(AveragePooling2D(pool_size=(3,3), strides=(2, 2)))
model.add(Flatten())
#全鏈接神經網絡
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
複製代碼
模型搭建完畢後,咱們開始訓練神經網絡。爲了能縮短訓練時間,我比較喜歡隨機選擇訓練集讓模型學習,這也是在 Keras 中使用 fit_generator 的緣由。一樣,損失函數會是交叉熵,由於咱們的任務是多類型分類問題。bash
gen = ImageDataGenerator()
train_generator = gen.flow(x_train, y_train, batch_size=batch_size)
model.compile(loss='categorical_crossentropy'
, optimizer=keras.optimizers.Adam()
, metrics=['accuracy']
)
model.fit_generator(train_generator, steps_per_epoch=batch_size, epochs=epochs)
複製代碼
執行完 fit 函數後,咱們對模型進行評估:網絡
train_score = model.evaluate(x_train, y_train, verbose=0)
print('Train loss:', train_score[0])
print('Train accuracy:', 100*train_score[1])
test_score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', test_score[0])
print('Test accuracy:', 100*test_score[1])
複製代碼
爲了避免出現過擬合,最終獲得以下結果,但當我增長epoch次數時,出現了過擬合現象:架構
Test loss: 2.27945706329
Test accuracy: 57.4254667071
Train loss: 0.223031098232
Train accuracy: 92.0512731201
複製代碼
最終搭建的面部表情識別模型準確率爲57%。app
咱們如今試着讓模型識別咱們本身找來的照片中的面部表情,由於單憑測試集中的錯誤率說明不了什麼。
img = image.load_img("/data/pablo.png", grayscale=True, target_size=(48, 48))
x = image.img_to_array(img)
x = np.expand_dims(x, axis = 0)
x /= 255
custom = model.predict(x)
emotion_analysis(custom[0])
x = np.array(x, 'float32')
x = x.reshape([48, 48]);
plt.gray()
plt.imshow(x)
plt.show()
複製代碼
將面部表情存儲爲數值,並按照從0到6打上標籤。Keras會生成一個輸出數組,包括這7個不一樣的表情分值。咱們能夠將每一個表情的預測可視化爲條形圖。
def emotion_analysis(emotions):
objects = ('angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral')
y_pos = np.arange(len(objects))
plt.bar(y_pos, emotions, align='center', alpha=0.5)
plt.xticks(y_pos, objects)
plt.ylabel('percentage')
plt.title('emotion')
plt.show()
複製代碼
若是你看過 NetFlix 出品的《毒梟》系列,你必定很熟悉這張照片。下面這張照片是大毒梟巴勃羅·埃斯科瓦爾被捕入獄時照的照片。用咱們剛纔搭建的模型對這張照片識別後,顯示巴勃羅當時的心情很是不錯。
接着咱們用第二張照片,馬龍·白蘭度在《教父》中飾演的「老頭子」考利昂看到兒子屍體時的畫面。測試結果顯示模型也能識別出考利昂痛苦悲傷的表情。
我還想測試一下發怒的表情,提到發怒,休·傑克曼演的「金剛狼」但是個典型,就是他了。我選了《X戰警》中金剛狼暴怒的圖片。測試結果顯示很是成功。
最後,讓模型挑戰一個高難度的照片:蒙娜麗莎的微笑。至今藝術家們仍沒有搞明白達芬奇的畫做《蒙娜麗莎》中人物當時的心情。用咱們的模型識別後,顯示當時蒙娜麗莎的心情很是平和天然。
在本文咱們構建了一個卷積神經網絡識別人類的面部表情。最終模型的準確率爲 57%,這個結果還能夠接受吧,由於當年 Kaggle 的那次比賽最高準確率才34%。若是對檢測到的圖像中的人臉進行處理,而非處理整個圖像,能進一步提升準確率。所以我在運行神經模型前,對圖像中的人臉作了些裁切工做。我計劃下一步訓練 Inception 中的預構建模型完成這個任務,到時候再和你們分享。
點擊這裏查看本項目代碼。
歡迎關注咱們,學習資源,AI教程,論文解讀,趣味項目,你想看的都在這裏!