毕业设计-人脸表情识别系统、人工智能
人臉表情識(shí)別系統(tǒng)
1. 前言
????在這個(gè)人工智能成為超級(jí)大熱門的時(shí)代,人臉表情識(shí)別已成為其中的一項(xiàng)研究熱點(diǎn),而卷積神經(jīng)網(wǎng)絡(luò)、深度信念網(wǎng)絡(luò)和多層感知器等相關(guān)算法在人臉面部表情識(shí)別領(lǐng)域的運(yùn)用最為廣泛。面部的表情中包含了太多的信息,輕微的表情變化都會(huì)反映出人心理的變化,可想而知如果機(jī)器能敏銳地識(shí)別人臉中表達(dá)的情感該是多么令人興奮的事。
????學(xué)習(xí)和研究了挺久的深度學(xué)習(xí),偶然看到IEEE上面一篇質(zhì)量很高的文章,里面介紹的是利用深度神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)的面部表情識(shí)別,研讀下來(lái)讓我深受啟發(fā)。于是自己動(dòng)手做了這個(gè)項(xiàng)目,如今SCI論文已投稿,這里特此將前期工作作個(gè)總結(jié),希望能給類似工作的朋友帶來(lái)一點(diǎn)幫助。由于論文尚未公開,這里使用的是已有的模型——如今CNN的主流框架之mini_XCEPTION,該模型性能也已是不錯(cuò)的了,論文中改進(jìn)的更高性能模型尚不便給出,后面會(huì)分享給大家,敬請(qǐng)關(guān)注。
2. 表情識(shí)別數(shù)據(jù)集
????目前,現(xiàn)有的公開的人臉表情數(shù)據(jù)集比較少,并且數(shù)量級(jí)比較小。比較有名的廣泛用于人臉表情識(shí)別系統(tǒng)的數(shù)據(jù)集Extended Cohn-Kanada (CK+)是由P.Lucy收集的。CK+數(shù)據(jù)集包含123?個(gè)對(duì)象的327?個(gè)被標(biāo)記的表情圖片序列,共分為正常、生氣、蔑視、厭惡、恐懼、開心和傷心七種表情。對(duì)于每一個(gè)圖片序列,只有最后一幀被提供了表情標(biāo)簽,所以共有327?個(gè)圖像被標(biāo)記。為了增加數(shù)據(jù),我們把每個(gè)視頻序列的最后三幀圖像作為訓(xùn)練樣本。這樣CK+數(shù)據(jù)總共被標(biāo)記的有981?張圖片。這個(gè)數(shù)據(jù)庫(kù)是人臉表情識(shí)別中比較流行的一個(gè)數(shù)據(jù)庫(kù),很多文章都會(huì)用到這個(gè)數(shù)據(jù)做測(cè)試,可通過(guò)下面的鏈接下載。
官網(wǎng)鏈接:The Extended Cohn-Kanade Dataset(CK+)
網(wǎng)盤鏈接:百度網(wǎng)盤下載(提取碼:8r15)
????Kaggle是Kaggle人臉表情分析比賽提供的一個(gè)數(shù)據(jù)集。該數(shù)據(jù)集含28709?張訓(xùn)練樣本,3859?張驗(yàn)證數(shù)據(jù)集和3859?張測(cè)試樣本,共35887?張包含生氣、厭惡、恐懼、高興、悲傷、驚訝和正常七種類別的圖像,圖像分辨率為48×48。該數(shù)據(jù)集中的圖像大都在平面和非平面上有旋轉(zhuǎn),并且很多圖像都有手、頭發(fā)和圍巾等的遮擋物的遮擋。該數(shù)據(jù)庫(kù)是2013年Kaggle比賽的數(shù)據(jù),由于這個(gè)數(shù)據(jù)庫(kù)大多是從網(wǎng)絡(luò)爬蟲下載的,存在一定的誤差性。這個(gè)數(shù)據(jù)庫(kù)的人為準(zhǔn)確率是65%±5%。
官網(wǎng)鏈接:FER2013
網(wǎng)盤鏈接:百度網(wǎng)盤下載(提取碼:t7xj)
????由于FER2013數(shù)據(jù)集數(shù)據(jù)更加齊全,同時(shí)更加符合實(shí)際生活的場(chǎng)景,所以這里主要選取FER2013訓(xùn)練和測(cè)試模型。為了防止網(wǎng)絡(luò)過(guò)快地過(guò)擬合,可以人為的做一些圖像變換,例如翻轉(zhuǎn),旋轉(zhuǎn),切割等。上述操作稱為數(shù)據(jù)增強(qiáng)。數(shù)據(jù)操作還有另一大好處是擴(kuò)大數(shù)據(jù)庫(kù)的數(shù)據(jù)量,使得訓(xùn)練的網(wǎng)絡(luò)魯棒性更強(qiáng)。下載數(shù)據(jù)集保存在fer2013的文件夾下,為了對(duì)數(shù)據(jù)集進(jìn)行處理,采用如下代碼載入和進(jìn)行圖片預(yù)處理:
import pandas as pd import cv2 import numpy as npdataset_path = 'fer2013/fer2013/fer2013.csv' # 文件保存位置 image_size=(48,48) # 圖片大小# 載入數(shù)據(jù) def load_fer2013():data = pd.read_csv(dataset_path)pixels = data['pixels'].tolist()width, height = 48, 48faces = []for pixel_sequence in pixels:face = [int(pixel) for pixel in pixel_sequence.split(' ')]face = np.asarray(face).reshape(width, height)face = cv2.resize(face.astype('uint8'),image_size)faces.append(face.astype('float32'))faces = np.asarray(faces)faces = np.expand_dims(faces, -1)emotions = pd.get_dummies(data['emotion']).as_matrix()return faces, emotions# 將數(shù)據(jù)歸一化 def preprocess_input(x, v2=True):x = x.astype('float32')x = x / 255.0if v2:x = x - 0.5x = x * 2.0return x載入數(shù)據(jù)后將數(shù)據(jù)集劃分為訓(xùn)練集和測(cè)試集,在程序中調(diào)用上面的函數(shù)代碼如下:
from load_and_process import load_fer2013 from load_and_process import preprocess_input from sklearn.model_selection import train_test_split# 載入數(shù)據(jù)集 faces, emotions = load_fer2013() faces = preprocess_input(faces) num_samples, num_classes = emotions.shape# 劃分訓(xùn)練、測(cè)試集 xtrain, xtest,ytrain,ytest = train_test_split(faces, emotions,test_size=0.2,shuffle=True)3. 搭建表情識(shí)別的模型
????接下來(lái)就是搭建表情識(shí)別的模型了,這里用到的是CNN的主流框架之mini_XCEPTION。XCEPTION是Google繼Inception后提出的對(duì)Inception v3的另一種改進(jìn),主要是采用深度可分離的卷積(depthwise separable convolution)來(lái)替換原來(lái)Inception v3中的卷積操作。XCEPTION的網(wǎng)絡(luò)結(jié)構(gòu)在ImageNet數(shù)據(jù)集(Inception v3的設(shè)計(jì)解決目標(biāo))上略優(yōu)于Inception v3,并且在包含3.5億個(gè)圖像甚至更大的圖像分類數(shù)據(jù)集上明顯優(yōu)于Inception v3,而兩個(gè)結(jié)構(gòu)保持了相同數(shù)目的參數(shù),性能增益來(lái)自于更加有效地使用模型參數(shù),詳細(xì)可參考論文:Xception: Deep Learning with Depthwise Separable Convolutions,論文Real-time Convolutional Neural Networks for Emotion and Gender Classification等。
????既然這樣的網(wǎng)絡(luò)能獲得更好結(jié)果又是主流,那當(dāng)然有必要作為對(duì)比算法實(shí)現(xiàn)以下了,這里博主模型這部分的代碼引用了GitHub:https://github.com/oarriaga/face_classification中的模型(其他地方也能找到這個(gè)模型的類似代碼),模型框圖如上圖所示,其代碼如下:
def mini_XCEPTION(input_shape, num_classes, l2_regularization=0.01):regularization = l2(l2_regularization)# baseimg_input = Input(input_shape)x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization,use_bias=False)(img_input)x = BatchNormalization()(x)x = Activation('relu')(x)x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)# module 1residual = Conv2D(16, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)x = SeparableConv2D(16, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(16, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])# module 2residual = Conv2D(32, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)x = SeparableConv2D(32, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(32, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])# module 3residual = Conv2D(64, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)x = SeparableConv2D(64, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(64, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])# module 4residual = Conv2D(128, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)x = SeparableConv2D(128, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(128, (3, 3), padding='same',kernel_regularizer=regularization,use_bias=False)(x)x = BatchNormalization()(x)x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])x = Conv2D(num_classes, (3, 3),#kernel_regularizer=regularization,padding='same')(x)x = GlobalAveragePooling2D()(x)output = Activation('softmax',name='predictions')(x)model = Model(img_input, output)return model4. 數(shù)據(jù)增強(qiáng)的批量訓(xùn)練
????神經(jīng)網(wǎng)絡(luò)的訓(xùn)練需要大量的數(shù)據(jù),數(shù)據(jù)的量決定了網(wǎng)絡(luò)模型可以達(dá)到的高度,網(wǎng)絡(luò)模型盡量地逼近這個(gè)高度。然而對(duì)于人臉表情的數(shù)據(jù)來(lái)說(shuō),都只存在少量的數(shù)據(jù)Extended Cohn-Kanada (CK+)的數(shù)據(jù)量是遠(yuǎn)遠(yuǎn)不夠的,并且CK+多是比較夸張的數(shù)據(jù)。Kaggle Fer2013數(shù)據(jù)集也不過(guò)只有3萬(wàn)多數(shù)據(jù)量,而且有很多遮擋、角度等外界影響因素。既然收集數(shù)據(jù)要花費(fèi)很大的人力物力,那么我們就用技術(shù)解決這個(gè)問(wèn)題,為避免重復(fù)開發(fā)首先還是看看有沒(méi)有寫好的庫(kù)。博主又通讀了遍Keras官方文檔,其中ImageDataGenerator的圖片生成器就可完成這一目標(biāo)。
為了盡量利用我們有限的訓(xùn)練數(shù)據(jù),我們將通過(guò)一系列隨機(jī)變換堆數(shù)據(jù)進(jìn)行提升,這樣我們的模型將看不到任何兩張完全相同的圖片,這有利于我們抑制過(guò)擬合,使得模型的泛化能力更好。在Keras中,這個(gè)步驟可以通過(guò)keras.preprocessing.image.ImageGenerator來(lái)實(shí)現(xiàn),這個(gè)類使你可以:在訓(xùn)練過(guò)程中,設(shè)置要施行的隨機(jī)變換通過(guò).flow或.flow_from_directory(directory)方法實(shí)例化一個(gè)針對(duì)圖像batch的生成器,這些生成器可以被用作keras模型相關(guān)方法的輸入,如fit_generator,evaluate_generator和predict_generator。——Keras官方文檔
????ImageDataGenerator()是一個(gè)圖片生成器,同時(shí)也可以在batch中對(duì)數(shù)據(jù)進(jìn)行增強(qiáng),擴(kuò)充數(shù)據(jù)集大小(比如進(jìn)行旋轉(zhuǎn),變形,歸一化等),增強(qiáng)模型的泛化能力。結(jié)合前面的模型和數(shù)據(jù)訓(xùn)練部分的代碼如下:
""" Description: 訓(xùn)練人臉表情識(shí)別程序 """from keras.callbacks import CSVLogger, ModelCheckpoint, EarlyStopping from keras.callbacks import ReduceLROnPlateau from keras.preprocessing.image import ImageDataGenerator from load_and_process import load_fer2013 from load_and_process import preprocess_input from models.cnn import mini_XCEPTION from sklearn.model_selection import train_test_split# 參數(shù) batch_size = 32 num_epochs = 10000 input_shape = (48, 48, 1) validation_split = .2 verbose = 1 num_classes = 7 patience = 50 base_path = 'models/'# 構(gòu)建模型 model = mini_XCEPTION(input_shape, num_classes) model.compile(optimizer='adam', # 優(yōu)化器采用adamloss='categorical_crossentropy', # 多分類的對(duì)數(shù)損失函數(shù)metrics=['accuracy']) model.summary()# 定義回調(diào)函數(shù) Callbacks 用于訓(xùn)練過(guò)程 log_file_path = base_path + '_emotion_training.log' csv_logger = CSVLogger(log_file_path, append=False) early_stop = EarlyStopping('val_loss', patience=patience) reduce_lr = ReduceLROnPlateau('val_loss', factor=0.1,patience=int(patience/4),verbose=1) # 模型位置及命名 trained_models_path = base_path + '_mini_XCEPTION' model_names = trained_models_path + '.{epoch:02d}-{val_acc:.2f}.hdf5'# 定義模型權(quán)重位置、命名等 model_checkpoint = ModelCheckpoint(model_names,'val_loss', verbose=1,save_best_only=True) callbacks = [model_checkpoint, csv_logger, early_stop, reduce_lr]# 載入數(shù)據(jù)集 faces, emotions = load_fer2013() faces = preprocess_input(faces) num_samples, num_classes = emotions.shape# 劃分訓(xùn)練、測(cè)試集 xtrain, xtest,ytrain,ytest = train_test_split(faces, emotions,test_size=0.2,shuffle=True)# 圖片產(chǎn)生器,在批量中對(duì)數(shù)據(jù)進(jìn)行增強(qiáng),擴(kuò)充數(shù)據(jù)集大小 data_generator = ImageDataGenerator(featurewise_center=False,featurewise_std_normalization=False,rotation_range=10,width_shift_range=0.1,height_shift_range=0.1,zoom_range=.1,horizontal_flip=True)# 利用數(shù)據(jù)增強(qiáng)進(jìn)行訓(xùn)練 model.fit_generator(data_generator.flow(xtrain, ytrain, batch_size),steps_per_epoch=len(xtrain) / batch_size,epochs=num_epochs,verbose=1, callbacks=callbacks,validation_data=(xtest,ytest))5. 系統(tǒng)UI界面的實(shí)現(xiàn)
????上面的模型訓(xùn)練好了,但對(duì)于我們來(lái)說(shuō)它的作用就只是知道了其準(zhǔn)確率還行,其實(shí)深度學(xué)習(xí)的目的最重要還是應(yīng)用,是時(shí)候用上面的模型做點(diǎn)酷酷的東西了。可不可以用上面的模型識(shí)別下自己表達(dá)的情緒呢?不如做個(gè)系統(tǒng)調(diào)取攝像頭對(duì)實(shí)時(shí)畫面中的表情進(jìn)行識(shí)別并顯示識(shí)別結(jié)果,既能可視化的檢測(cè)模型的實(shí)用性能,同時(shí)使得整個(gè)項(xiàng)目生動(dòng)有趣激發(fā)自己的創(chuàng)造性,當(dāng)你向別人介紹你的項(xiàng)目時(shí)也顯得高大上。這里采用PyQt5進(jìn)行設(shè)計(jì),首先看一下最后的效果圖,運(yùn)行后的界面如下:
????設(shè)計(jì)功能:一、可選擇模型文件后基于該模型進(jìn)行識(shí)別;二、打開攝像頭識(shí)別實(shí)時(shí)畫面中的人臉表情;三、選擇一張人臉圖片,對(duì)其中的表情進(jìn)行識(shí)別。選擇一張圖片測(cè)試識(shí)別效果,如下圖所示:
本文轉(zhuǎn)載自思緒無(wú)限:人臉表情識(shí)別系統(tǒng)介紹——上篇(python實(shí)現(xiàn),含UI界面及完整代碼)_思緒無(wú)限的博客-CSDN博客_人臉表情識(shí)別系統(tǒng)
感謝大家的支持。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的毕业设计-人脸表情识别系统、人工智能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: chatbot1_2 RNN简单实现
- 下一篇: 9 计算机组成原理第五章 中央处理器