吳 晶, 趙厚科
(1.東北石油大學(xué)秦皇島分校,河北 秦皇島 066004;2.西南民族大學(xué)電氣信息工程學(xué)院,四川 成都 610225)
一個(gè)基于深度學(xué)習(xí)的人臉識(shí)別系統(tǒng)是學(xué)習(xí)機(jī)器學(xué)習(xí)的最好的一個(gè)案例。系統(tǒng)是基于深度學(xué)習(xí)平臺(tái)Tensorflow所搭建的人臉識(shí)別系統(tǒng),通過攝像頭獲取視頻,使用opencv自帶的分類器定位人臉[1],并且在每一幀圖像中截取人臉,使用卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練人臉識(shí)別。
系統(tǒng)共分為四個(gè)部分,實(shí)時(shí)人臉截取模塊、圖片處理模塊、CNN搭建和訓(xùn)練模塊以及測(cè)試模塊。
實(shí)時(shí)人臉截取主要負(fù)責(zé)采集人臉圖片,通過USB攝像頭截取人臉數(shù)據(jù),使用OpenCV定位人臉,同一數(shù)據(jù)格式,并最終保存人臉圖片。
本地圖片處理模塊主要用于處理在網(wǎng)絡(luò)上下載下來作為第三個(gè)分類類別使用的圖片,其主要功能是將圖片讀入,使用opencv定位人臉,然后將人臉圖片保存成我設(shè)定好的規(guī)格以便使用。
CNN搭建和訓(xùn)練模塊主要完成搭建神經(jīng)網(wǎng)絡(luò)、劃分訓(xùn)練集與測(cè)試集,深度學(xué)習(xí)訓(xùn)練,訓(xùn)練模型的保存,是整個(gè)系統(tǒng)的關(guān)鍵部分[2]。
測(cè)試部分主要來調(diào)用攝像頭捕獲人臉圖片,然后讀入之前保存好的訓(xùn)練成熟的網(wǎng)絡(luò)模型進(jìn)行識(shí)別。
卷積神經(jīng)網(wǎng)絡(luò)是一種具有卷積運(yùn)算和深度結(jié)構(gòu)的前饋神經(jīng)網(wǎng)絡(luò),是深度學(xué)習(xí)的典型算法之一。卷積神經(jīng)網(wǎng)絡(luò)具有表示學(xué)習(xí)能力,能夠根據(jù)其層次結(jié)構(gòu)對(duì)輸入信息進(jìn)行分類,基本框架見圖1。
圖1 卷積神經(jīng)網(wǎng)絡(luò)基本框架
2.1.1 卷積層
其中在卷積神經(jīng)網(wǎng)絡(luò)中存在著由許多卷積單元組成的卷積層[3],并且可以通過利用反向傳播算法來優(yōu)化各個(gè)卷積單元的參數(shù)。其中提取輸入的不同特征是由卷積運(yùn)算提供的,第一卷積層只能提取邊緣、直線和角度等低級(jí)特征。更多的網(wǎng)絡(luò)層可以迭代地從低級(jí)特征中提取更復(fù)雜的特征??梢詫⒚總€(gè)過濾器描繪成一個(gè)窗口,該窗口在圖像的尺寸上滑動(dòng)并檢測(cè)屬性。濾鏡在圖像上滑動(dòng)的像素?cái)?shù)量稱為步幅。步幅為1意味著濾波器一次移動(dòng)一個(gè)像素,其中2的步幅將向前跳過2個(gè)像素。
圖2 提取特征向量并簡(jiǎn)化數(shù)據(jù)量
在圖2所示的例子中,可以看到一個(gè)垂直線檢測(cè)器。原始圖像為6×6,它使用3×3濾鏡進(jìn)行掃描,步長(zhǎng)為1,從而產(chǎn)生4×4尺寸輸出。而過濾器僅對(duì)其視野左右列中的部分感興趣。通過對(duì)圖像的輸入求和并乘以3×3濾波器的配置,得到8+1+2-5-3-2=-2。然后濾波器向右移動(dòng)一步,然后計(jì)算0+6+3-8-0-1=0。0然后進(jìn)入-2右側(cè)的位置。此過程將持續(xù)到4×4網(wǎng)格完成為止。之后,下一個(gè)特征圖將使用它自己的唯一過濾器/內(nèi)核矩陣計(jì)算自己的值。
2.1.2 池化層
圖3顯示的池化層處理過程。池化層的目的是為了來進(jìn)一步降低維度,通過聚合卷積層收集的值或所謂的子采樣進(jìn)行降維。除了為模型提供一些正則化的方案以避免過度擬合之外,這還將減少計(jì)算量。它們遵循與卷積層相同的滑動(dòng)窗口思想,但不是計(jì)算所有值,而是選擇其輸入的最大值或平均值。這分別稱為最大池化和平均池化。
圖3 池化層處理過程
這兩個(gè)組件是卷積層的關(guān)鍵構(gòu)建塊。然后,通常會(huì)重復(fù)此方法,進(jìn)一步減少特征圖的大小尺寸,而且會(huì)增加其深度。每個(gè)特征圖將專門識(shí)別它自己獨(dú)特的形狀。在卷積結(jié)束時(shí),會(huì)放置一個(gè)完全連接的圖層,其具有激活功能,例如Relu或Selu,用于將尺寸重新整形為適合的尺寸送入分類器。例如,如果你的最終轉(zhuǎn)換層為3×3×128矩陣,但你只預(yù)測(cè)10個(gè)不同的類,則需要將其重新整形為1×1152向量,并在輸入分類器之前逐漸減小其大小。完全連接的層也將學(xué)習(xí)它們自己的特征,見圖4。
2.2.1 Haar-like特征
Haar特征分為:邊緣、線性、中心特征和對(duì)角線特征,這些特征相互組合成特征模板。特征模板內(nèi)有白色和黑色兩種矩形,模板的特征值定義為白色矩形和減去黑色矩形(在opencv實(shí)現(xiàn)中為黑色-白色)。
圖4 神經(jīng)網(wǎng)絡(luò)框架總圖
Haar的特征值反映了圖像灰度的變化。例如,面部的某些特征可以簡(jiǎn)單地用矩形特征來說明,但是矩形特征只對(duì)一些簡(jiǎn)單的圖形結(jié)構(gòu)敏感,比如邊緣和線段,所以這些特征模板只能描述特定方向,例如水平、垂直、傾斜的人臉結(jié)構(gòu)。如果將這樣的矩形設(shè)置在非人臉臉區(qū)域的話,計(jì)算出的特征值應(yīng)該和臉部特征值有所不同,所以這些矩形為了區(qū)別臉部和非臉,去定量化臉部特征[4]。
圖5 人臉識(shí)別特征模板
圖6 矩形特征在人臉圖像的特征匹配
2.2.2 特征模板
如圖5所示,人臉的構(gòu)造特征可以根據(jù)矩形的特征簡(jiǎn)單地描繪出來。例如,圖6中眼睛比臉頰顏色深,鼻子的兩側(cè)比鼻子的梁顏色深,嘴唇比周圍的顏色深等。
對(duì)于24×24像素分辨率的圖像,矩陣特征的數(shù)量約為160000。此時(shí),需要通過一種特定的算法來過濾合適的矩陣特征,并將它們組合成一個(gè)強(qiáng)分類器來檢測(cè)人臉。
在得到矩形特征后,計(jì)算矩形特征的值。定義一個(gè)坐標(biāo)為A(x,y)的積分圖,這個(gè)積分圖的定義是其人臉圖像左上角的所有像素之和,因此,對(duì)每個(gè)像素進(jìn)行少量計(jì)算就可以得到的“積分圖”并且可以同時(shí)計(jì)算不同尺度的矩形特征值,從而大幅度的提高了計(jì)算效率。
對(duì)于圖像中的點(diǎn)a(x,y),積分圖被定義為ii(x,y):
其中i(x',y')為點(diǎn)(x',y')處的像素值。
圖7 積分圖
坐標(biāo)a(x,y)的積分圖定義為左上角矩陣中所有像素的和,如圖7陰影部分所示:
由此可以看出,要計(jì)算兩個(gè)區(qū)域像素值之間的差(即計(jì)算矩形模板的特征值),只需使用特征區(qū)域端點(diǎn)的積分圖進(jìn)行簡(jiǎn)單的加減運(yùn)算即可。積分圖法可以快速計(jì)算矩形特征的特征值。
圖8 特征模板的特征值計(jì)算原理圖
如圖8所示,特征模板的特征值 = pixel area(B)-pixel area(A) =[ii4 + ii1 - (ii2 + ii3)] -[ii6 + ii3 - (ii4 + ii5)]。
選擇用opencv來完成人臉截取。首先給opencv視頻來源,可以來自一段已存好的視頻,也可以直接來自USB攝像頭(cv2.VideoCapture(camera_idx)),選擇使用USB攝像頭來進(jìn)行實(shí)時(shí)截取。然后選擇opencv自帶的人臉識(shí)別分類器(haarcascade_frontalface_alt2.xml),之后循環(huán)來讀取視頻里每一幀的圖像進(jìn)行人臉截取。
首先把當(dāng)前圖像轉(zhuǎn)換喂灰度圖像,這樣能大幅減少數(shù)據(jù)量,以便計(jì)算特征,然后開始進(jìn)行人臉檢測(cè),調(diào)用classfier.detectMultiScale函數(shù)其中選取1.2為圖片縮放比例,和2個(gè)檢測(cè)有效點(diǎn),其參數(shù)為grey, scaleFactor = 1.2, minNeighbors = 3, minSize = (32, 32),當(dāng)這個(gè)函數(shù)返回值的len長(zhǎng)度大于0時(shí)檢測(cè)到人臉然后保存到本地,當(dāng)循環(huán)到達(dá)設(shè)定的要截取人臉數(shù)據(jù)量時(shí)退出循環(huán)。
處理圖片也用opencv大致步驟與第一步出不多,只是寫2個(gè)循環(huán)來讀取圖片、處理圖片、保存圖片。把圖片處理成64×64大小的圖片,方便以后訓(xùn)練。
學(xué)習(xí)平臺(tái)選擇Tensorflow2.0,并且導(dǎo)入opencv和sklearn,由于大部分功能都用不到Tf2.0的特性于是添加下面兩行代碼來讓使用V1版本的功能import tensorflow.compat.v1 as tf和 tf.disable_v2_behavior()。接下來需要定義幾個(gè)函數(shù)來實(shí)現(xiàn)一些功能,他們分別是:
def getPaddingSize(img):
此函數(shù)的作用是給2維圖像一個(gè)坐標(biāo)其中要用//整除符號(hào),否則結(jié)果會(huì)進(jìn)行偏移。函數(shù)返回 top, bottom, left, right。4個(gè)值。
def readData(path , h=size, w=size):此函數(shù)的主要功能是讀取圖片數(shù)據(jù)后先將圖片放大, 擴(kuò)充圖片邊緣部分,其次將圖片數(shù)據(jù)與標(biāo)簽轉(zhuǎn)換成數(shù)組、隨機(jī)劃分測(cè)試集與訓(xùn)練集,設(shè)置圖片數(shù)據(jù)的總數(shù),圖片的高、寬、通道,接下來將數(shù)據(jù)轉(zhuǎn)換成小于1的數(shù),在此函數(shù)中設(shè)置一個(gè)圖片塊,每次取100張圖片。
def weightVariable(shape):
權(quán)重變量,函數(shù)返回tf.Variable(tf.random_normal(shape, stddev=0.01))
def biasVariable(shape):
函數(shù)返回tf.Variable(tf.random_normal(shape))
def conv2d(x, W):2維的卷積層,用于圖片的卷積, 輸入圖像的通道數(shù)= x (灰度圖像),卷積核的種類數(shù)=W, 卷積核的shape是[1,1,1,1]的,padding = 'SAME'輸入圖片大小和輸出圖片大小是一致的。
def maxPool(x):
max pooling是CNN當(dāng)中的最大值池化操作,函數(shù)返tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
def dropout(x, keep):
返回tf.nn.dropout(x, keep)
def cnnLayer():
第一層:卷積核大小(3,3),輸入通道(3),輸出通道(32),卷積,池化,減少過擬合,隨機(jī)讓某些權(quán)重不更新。
第二層:卷積核大小(3,3),輸入通道(32),輸出通道(64),卷積,池化,減少過擬合。
第三層:卷積核大小(3,3),輸入通道(64),輸出通道(64),卷積,池化,減少過擬合。
輸出層:二維張量,1*512矩陣卷積,共2個(gè)卷積,對(duì)應(yīng)開始的ys長(zhǎng)度為2,最后的分類,結(jié)果為1*1*2softmax和sigmoid都是基于logistic分類算法,一個(gè)是多分類一個(gè)是二分類。
def cnnTrain():
開始數(shù)據(jù)訓(xùn)練以及評(píng)測(cè),調(diào)用cnnLayer(),比較標(biāo)簽是否相等,再求的所有數(shù)的平均值,tf.cast(強(qiáng)制轉(zhuǎn)換類型),將loss與accuracy保存以供tensorboard使用,數(shù)據(jù)保存器的初始化,開始循環(huán),每次取128張圖片,開始訓(xùn)練數(shù)據(jù),同時(shí)訓(xùn)練三個(gè)變量,返回三個(gè)數(shù)據(jù),打印損失,獲取測(cè)試數(shù)據(jù)的準(zhǔn)確率,準(zhǔn)確率大于0.98時(shí)保存訓(xùn)練完成的模型,以便調(diào)用。
在剛才train_faces.py的基礎(chǔ)上再定義一個(gè)函數(shù)以便于驗(yàn)證模型,同樣使用opencv來幫助驗(yàn)證模型,首先加載剛剛訓(xùn)練好的模型。
saver = tf.train.Saver()
sess = tf.Session()
saver.restore(sess, tf.train.latest_checkpoint('存放模型的目錄'))
然后定義一個(gè)函數(shù)用來讀取圖像到模型中進(jìn)行比對(duì),是否為模型訓(xùn)練里的臉,并返回true或false。接下來就要調(diào)用opencv截取每一幀視頻圖像截取人臉作為參數(shù)傳遞給驗(yàn)證函數(shù),并且在人臉框旁邊顯示這張臉人主人是誰(shuí)。
此項(xiàng)目的最重要的部分有兩個(gè),首先是圖片數(shù)據(jù)的處理,必須將圖片處理成合適的大小來進(jìn)行訓(xùn)練,這樣能加快效率,其次是模型訓(xùn)練,這是整個(gè)項(xiàng)目的重中之重,這里總共用到了2個(gè)卷積,因?yàn)橛捎陔[私問題不能隨便使用別人的人臉數(shù)據(jù),這里的數(shù)據(jù)主要是作者的人臉數(shù)據(jù)和少部分網(wǎng)上公開無版權(quán)糾紛的人臉數(shù)據(jù)庫(kù),數(shù)據(jù)不多,這個(gè)項(xiàng)目主要區(qū)分作者和其他人的臉,如果想訓(xùn)練模型識(shí)別多個(gè)人的人臉可以在數(shù)據(jù)處理時(shí)加幾個(gè)循環(huán),大體框架不變,訓(xùn)練時(shí)多幾個(gè)變量即可完成項(xiàng)目。