Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
章相關(guān)引用及參考:映維網(wǎng)
記錄手部動(dòng)作并將其轉(zhuǎn)換為文字
(映維網(wǎng) 2018年04月19日)意大利初創(chuàng)公司Limix開發(fā)了一種名為Talking Hands的手套,其可以記錄手部動(dòng)作并將其轉(zhuǎn)換為文字,轉(zhuǎn)發(fā)至智能手機(jī)設(shè)備,然后再通過語音合成器進(jìn)行播放。他們希望以這種方式來彌合大多數(shù)聾障人士所面臨的通信障礙。
Limix的創(chuàng)始人Francesco Pezzuoli說道:“Talking Hands不僅可以翻譯每一個(gè)字母,而且它的可定制程度非常高:用戶可以記錄他/她的手語,然后Talking Hands就會(huì)翻譯它們。這是一種可穿戴設(shè)備,不需要任何外部攝像頭或計(jì)算機(jī),因此用戶隨時(shí)隨地都可以使用它。”
該項(xiàng)目始于一年前,當(dāng)時(shí)是作為L(zhǎng)imix,意大利國家聾人協(xié)會(huì)(ENS),以及專門教導(dǎo)聾啞學(xué)生的意大利公立高中I.S.I.S.S. Magarotto之間的合作產(chǎn)物。然而,人們告訴Pezzuoli和另一位聯(lián)合創(chuàng)始人Dario Corona說這一概念不會(huì)成功,因?yàn)樵O(shè)備無法測(cè)量細(xì)微的手指動(dòng)作。但他們堅(jiān)持不懈,并最終研發(fā)出可行的技術(shù)。現(xiàn)在,他們正準(zhǔn)備在2018年6月推出第一個(gè)工業(yè)原型。
他們的概念成為了今年The Chivas Venture競(jìng)賽的最終入圍項(xiàng)目之一,并有機(jī)會(huì)競(jìng)逐100萬美元的投資。在今年5月,最終入選者將乘飛機(jī)前往阿姆斯特丹參加最終的決賽。屆時(shí)他們將有五分鐘時(shí)間向?qū)<以u(píng)審團(tuán)推銷他們的項(xiàng)目。對(duì)于The Chivas Venture的風(fēng)投,開發(fā)團(tuán)隊(duì)希望這可以為工業(yè)原型的生產(chǎn)和擴(kuò)展提供資金支持。
Pezzuoli解釋說:“主要的問題是,非手語者通常不太了解手語。他們可能甚至沒有意識(shí)到美國手語(和其他手語,如英國手語和中國手語)是非常不同的語言,其有著自己的語法和措辭,而不是口頭語言的單詞重述。”
Talking Hands能夠繞開這個(gè)問題,因?yàn)槠湓试S每個(gè)用戶通過應(yīng)用程序創(chuàng)建和自定義他們自己的手語,并將其直接鏈接到智能手機(jī)。他們可以創(chuàng)建專用于不同情況的字典,例如在醫(yī)療緊急情況下需要與醫(yī)生溝通的常用詞語。
Pezzuoli聲稱:“從來沒有人能夠發(fā)現(xiàn)和實(shí)現(xiàn)像我們這樣簡(jiǎn)單,低成本和有用的解決方案。Talking Hands的首次生產(chǎn)成本約為500歐元,包含一切,因此與市場(chǎng)上的其他手套相比,它的價(jià)格相對(duì)較低。”
具體操作:
用戶將Talking Hands應(yīng)用下載到移動(dòng)設(shè)備上。
用戶將應(yīng)用的口頭語言設(shè)置為英語和意大利語等語言,將其作為手語識(shí)別的輸出語言。
然后,用戶可以在穿戴手套時(shí)錄制手語,然后系統(tǒng)會(huì)將其與字母,單詞或整個(gè)短語相關(guān)聯(lián)。
每當(dāng)用戶重復(fù)該手語時(shí),智能手機(jī)都會(huì)代表用戶說出相應(yīng)的詞語。
Talking Hands可以翻譯世界各地使用的幾種不同手語:ASL(美國手語),BSL(英國手語),CSL(中國手語)等等。
Talking Hands同時(shí)可以與增強(qiáng)現(xiàn)實(shí)系統(tǒng)進(jìn)行交互,從而進(jìn)行員工培訓(xùn),與虛擬博物館和游戲控制器交互。
意大利國立聾人高等教育研究所(National Institute for Higher Education of Deaf People)的Rita Antoniozzi教授解釋說:“Talking Hands可以幫助聾啞人擺脫沉默,使他們能夠與不懂手語的人進(jìn)行第一范式的溝通。”她認(rèn)為,這項(xiàng)技術(shù)將能為失聰用戶提供支持,使他們能夠?qū)崿F(xiàn)更大程度的獨(dú)立性和平等性。
但對(duì)Pezzuoli而言,平等性的好處在很大程度上是雙向的:“我想證明技術(shù)可以成為統(tǒng)一和悅?cè)说牧α浚谷顺蔀橹行模@樣我們就可以創(chuàng)建并擴(kuò)大這種關(guān)系,納入殘疾人,并與他們的世界和文化融合在一起。”他補(bǔ)充說,殘疾人士看待世界的不同方式實(shí)際上是一項(xiàng)重要資產(chǎn),它可以帶來創(chuàng)造性思維和創(chuàng)新,因此賦予他們“聲音”不僅對(duì)聾人社區(qū)有好處,其對(duì)整個(gè)社會(huì)都有很大的益處。
原文鏈接:https://yivian.com/news/44228.html
文共4732字,預(yù)計(jì)學(xué)習(xí)時(shí)長(zhǎng)15分鐘
現(xiàn)在的年輕人聊起天來都是一場(chǎng)場(chǎng)你來我往的表情包大戰(zhàn)。稍有不慎,就會(huì)立馬敗下陣來。
你可能擁有數(shù)G個(gè)表情包存圖,但總是苦于表情包太多太亂,每次挑選都是曠日持久。等好不容易終于選中一張滿意的表情包,卻發(fā)現(xiàn)對(duì)方早已切到下一回合。
要是有個(gè)功能可以把表情包一鍵分類就好了。這可能,會(huì)隨著FER(面部表情識(shí)別技術(shù))的發(fā)展成為現(xiàn)實(shí)。
表情識(shí)別vs人臉識(shí)別
面部表情識(shí)別技術(shù)源于1971年心理學(xué)家Ekman和Friesen的一項(xiàng)研究,他們提出人類主要有六種基本情感,每種情感以唯一的表情來反映當(dāng)時(shí)的心理活動(dòng),這六種情感分別是憤怒(anger)、高興(happiness)、悲傷 (sadness)、驚訝(surprise)、厭惡(disgust)和恐懼(fear)。
盡管人類的情感維度和表情復(fù)雜度遠(yuǎn)不是數(shù)字6可以量化的,但總體而言,這6種也差不多夠描述了。
事實(shí)上,表情識(shí)別技術(shù)差不多可以算是在人臉識(shí)別技術(shù)的基礎(chǔ)上發(fā)展而來的。因此,表情識(shí)別也需要依賴于人臉的特征點(diǎn)檢測(cè)。
所謂的特征點(diǎn),就是預(yù)先定義的一組臉部或五官輪廓的點(diǎn)。在人臉特征點(diǎn)檢測(cè)中,通常我們比較關(guān)注的特征點(diǎn)一般位于眉毛、眼睛、嘴巴的位置,而鼻子在各種表情中的位置變化較不明顯,因此很多研究中都忽略對(duì)鼻子位置的特征點(diǎn)進(jìn)行檢測(cè)。
圖片來源:shutterlock
但兩者還是有區(qū)別的,表情識(shí)別從技術(shù)上來說還是比人臉識(shí)別要更加復(fù)雜。人臉識(shí)別是一個(gè)靜態(tài)識(shí)別問題,最經(jīng)典的人臉識(shí)別案例就是輸入兩張人臉照片,然后讓機(jī)器去判定兩張臉是不是屬于同一個(gè)人。而表情識(shí)別是給定一個(gè)人臉的連續(xù)動(dòng)作幀,是一個(gè)時(shí)間段內(nèi)表情變化的動(dòng)態(tài)判定問題。
人臉識(shí)別實(shí)際上是個(gè)去表情的過程,不管作出什么表情,不管是哭還是笑,都要想辦法去識(shí)別為同一個(gè)人。然而表情識(shí)別卻是放大表情的過程,對(duì)于同一個(gè)人,通過觀察表情變化來推斷其情緒的起伏。
圖片來源:shutterlock
相比于人臉識(shí)別,表情識(shí)別的動(dòng)態(tài)不確定性成分更大,不僅需要做到精確,而且需要做到實(shí)時(shí)。如果憤怒被檢測(cè)為悲傷,或者當(dāng)前檢測(cè)的表情已經(jīng)是三秒前的表情狀態(tài)了,那肯定都是沒有辦法滿足實(shí)際應(yīng)用需求的。
說到應(yīng)用,人臉識(shí)別最常見的應(yīng)用場(chǎng)景可能要數(shù)“身份驗(yàn)證”,而表情識(shí)別除了我們上面提到的能進(jìn)行表情分類外,還可以廣泛應(yīng)用于多個(gè)領(lǐng)域。
比如用于電影制作,往后不再需要設(shè)計(jì)動(dòng)畫,只需要將真人的表情動(dòng)作直接映射即可。用于產(chǎn)品投放前的反響測(cè)試,則可以通過分析被試者的表情來預(yù)測(cè)用戶體驗(yàn)。用于公安的審問環(huán)節(jié),可以通過觀察受審者的細(xì)微表情變化來幫助判斷其證詞是否屬實(shí)。當(dāng)然,在未來,如果機(jī)器能夠通過識(shí)別我們的表情來為我們提供個(gè)性化的服務(wù),就能實(shí)現(xiàn)更好的人機(jī)交互。
圖中右下角顯示原始表情,根據(jù)表情來進(jìn)行四川變臉。
當(dāng)表情識(shí)別遇上深度學(xué)習(xí)
目前,深度學(xué)習(xí)已強(qiáng)勢(shì)滲透進(jìn)各個(gè)學(xué)科各個(gè)領(lǐng)域,大數(shù)據(jù)已成為這個(gè)時(shí)代最標(biāo)志的特征之一。要用深度學(xué)習(xí)來做表情識(shí)別,第一步自然是選用一個(gè)數(shù)據(jù)豐富的表情庫,目前比較常用的表情庫主要有FER2013人臉數(shù)據(jù)集、日本ATR技術(shù)研究所建立的JAFFE日本女性表情數(shù)據(jù)庫以及美國CMU機(jī)器人研究所和心理學(xué)系共同建立的CKACFEID人臉表情數(shù)據(jù)庫。
JAFFE日本女性表情數(shù)據(jù)庫
總體來說,基于深度學(xué)習(xí)的表情識(shí)別一般分為以下幾個(gè)步驟:
1)圖像獲取:通過攝像頭等來獲得圖像輸入。
2)圖像預(yù)處理:對(duì)圖像中人臉識(shí)別子區(qū)域進(jìn)行檢測(cè),從而分割出人臉并去掉背景和無關(guān)區(qū)域。然后,進(jìn)一步對(duì)圖像中的人臉進(jìn)行標(biāo)定。目前IntraFace是最常用的人臉標(biāo)定方法,通過使用級(jí)聯(lián)人臉關(guān)鍵特征點(diǎn)定位(SDM),可準(zhǔn)確預(yù)測(cè)49個(gè)關(guān)鍵點(diǎn)。為了保證數(shù)據(jù)足夠充分,可以采用旋轉(zhuǎn)、翻轉(zhuǎn)、縮放等圖像增強(qiáng)操作,甚至可以利用現(xiàn)在大火的GAN來輔助生成更多的訓(xùn)練數(shù)據(jù)。
至此,準(zhǔn)備工作可還沒完事。由于圖像中不同光照強(qiáng)度和頭部姿態(tài)對(duì)表情識(shí)別的效果影響巨大,所以在開始正式工作前,還需要對(duì)光照和姿態(tài)做歸一化處理。不必?fù)?dān)心,站在巨人肩膀上的我們有很多現(xiàn)成的歸一化方法,比如使用INFace工具箱對(duì)光照進(jìn)行歸一化,以及使用FF-GAN,TP-GAN,DR-GAN這些基于GAN的深度模型來矯正面部姿態(tài)從而生成正面人臉。
基于深度學(xué)習(xí)的面部表情識(shí)別系統(tǒng)
3)特征學(xué)習(xí)深度網(wǎng)絡(luò)
傳統(tǒng)表情識(shí)別技術(shù)和深度表情識(shí)別技術(shù)最大的區(qū)別就在于特征學(xué)習(xí)的方式不同。傳統(tǒng)表情識(shí)別技術(shù)的特征提取方法主要有Gabor小波變換、局部二值模式(LBP)、局部線性嵌入(LLE)、梯度方向直方圖(HOG)等。
近些年來,有越來越多的深度網(wǎng)絡(luò)被用于FER,其中包括深度置信網(wǎng)絡(luò)DBN、遞歸神經(jīng)網(wǎng)絡(luò)RNN以及卷積神經(jīng)網(wǎng)絡(luò)CNN等。
以CNN為例,面部表情識(shí)別的CNN框架如下圖所示,與經(jīng)典的卷積神經(jīng)網(wǎng)絡(luò)無甚差別,主要也是包含輸入層、卷積層、全連接層和輸出層。
面部表情識(shí)別CNN架構(gòu)(改編自 埃因霍芬理工大學(xué)PARsE結(jié)構(gòu)圖)
其中,通過卷積操作來創(chuàng)建特征映射,將卷積核挨個(gè)與圖像進(jìn)行卷積,從而創(chuàng)建一組要素圖,并在其后通過池化(pooling)操作來降維。
CNN表情識(shí)別網(wǎng)絡(luò)中使用卷積和最大池化操作
通常,在致密層(又稱為全連接層)的末端可以加上損失層,目的是修正正反向的傳播誤差,此后網(wǎng)絡(luò)輸出的直接就是每個(gè)輸入樣本的表情分類預(yù)測(cè)概率。當(dāng)提供的數(shù)據(jù)越多,網(wǎng)絡(luò)可以逐步進(jìn)行微調(diào),直至損失最小。看起來好像我們?cè)O(shè)置的網(wǎng)絡(luò)節(jié)點(diǎn)越多,模型的表達(dá)能力就會(huì)越好,但這也同時(shí)會(huì)導(dǎo)致訓(xùn)練數(shù)據(jù)容易陷入過擬合狀態(tài)。一般使用Dropout來解決過擬合問題,該方法不僅可以保證模型在訓(xùn)練期間的敏感性也可以保持框架的必要復(fù)雜度。
神經(jīng)網(wǎng)絡(luò)訓(xùn)練:前向傳播(左)和后向傳播(右)
輸出層常用Sigmoid或者Softmax作為激活函數(shù),通過激活函數(shù)將神經(jīng)元的輸入映射到輸出端。實(shí)際上,激活函數(shù)并不是要激活什么,而是需要把激活的神經(jīng)元特征保留并映射出來,其他的數(shù)據(jù)屬于冗余就被剔掉了。在輸出層我們就能直接得到每個(gè)表情所屬的情緒類別及相應(yīng)概率。
盡管這看起來并不難,但表情識(shí)別除面臨光照變化、非正面頭部姿態(tài)等帶來的挑戰(zhàn)之外,對(duì)低強(qiáng)度的表情識(shí)別也較為困難;并且,理想的表情數(shù)據(jù)庫應(yīng)該包含各個(gè)種族、各個(gè)年齡階段的各種表情,除了數(shù)據(jù)獲取的難度外,對(duì)大量復(fù)雜自然場(chǎng)景下的人臉進(jìn)行精準(zhǔn)標(biāo)注也是一大難點(diǎn)。但隨著數(shù)據(jù)的豐富和算法的改進(jìn),這些都將不會(huì)是什么大問題。
表情識(shí)別太高端?不,你也可以!
下面,我們將通過實(shí)例教你如何實(shí)現(xiàn)表情識(shí)別。
首先,請(qǐng)確保你的電腦上已經(jīng)安裝和配置好Keras、Flask和OpenCV。
然后,選擇一個(gè)合適的表情庫,在這個(gè)實(shí)例中,我們選擇FER2013表情庫。
這個(gè)數(shù)據(jù)集中大約包含36000張大小為48*48像素的灰度圖像,并且都已自動(dòng)調(diào)整過,基本每張人臉在圖像中的位置和所占比例都差不多。除了心理學(xué)家Ekman和Friesen提出的6種情緒外,這里加入了一種新的情緒—中性(neutral)。每種情緒對(duì)應(yīng)一個(gè)數(shù)字類別,0=Angry(憤怒), 1=Disgust(厭惡), 2=Fear(恐懼), 3=Happy(高興), 4=Sad(悲傷), 5=Surprise(驚訝), 6=Neutral(中性)。
現(xiàn)在,正式工作開始。
原始數(shù)據(jù)由圖像每個(gè)像素灰度值的數(shù)組數(shù)據(jù)組成,我們將數(shù)據(jù)轉(zhuǎn)換為原始圖像并將其拆分放進(jìn)多個(gè)子文件中。其中,80%的數(shù)據(jù)放進(jìn)訓(xùn)練集中,剩余20%的數(shù)據(jù)用于測(cè)試。
images/ train/ angry/ disgust/ fear/ happy/ neutral/ sad/ surprise/ validation/ angry/ disgust/ fear/ happy/ neutral/ sad/ surprise/
首先讓我們看看我們的圖像長(zhǎng)什么樣子:
# display some images for every different expression import numpy as np import seaborn as sns from keras.preprocessing.image import load_img, img_to_array import matplotlib.pyplot as plt import os # size of the image: 48*48 pixels pic_size=48 # input path for the images base_path="../input/images/images/" plt.figure(0, figsize=(12,20)) cpt=0 for expression in os.listdir(base_path + "train/"): for i in range(1,6): cpt=cpt + 1 plt.subplot(7,5,cpt) img=load_img(base_path + "train/" + expression + "/" +os.listdir(base_path + "train/" + expression)[i], target_size=(pic_size, pic_size)) plt.imshow(img, cmap="gray") plt.tight_layout() plt.show()
部分訓(xùn)練樣本
你能猜出這些圖像對(duì)應(yīng)的表情么?
這對(duì)人類來說可能非常簡(jiǎn)單,但對(duì)于機(jī)器來說還是相當(dāng)具有挑戰(zhàn)性的。畢竟上面這些圖像分辨率不高,臉也不在同一位置,一些圖上還有文字,甚至很多圖都有手對(duì)面部進(jìn)行了遮擋。
但與此同時(shí),越復(fù)雜多樣的圖片訓(xùn)練出的模型泛化能力就會(huì)越好。
# count number of train images for each expression for expression in os.listdir(base_path + "train"): print(str(len(os.listdir(base_path + "train/" + expression))) + " " + expression + " images")
數(shù)一下每種表情的數(shù)量,我們得到:
4103 fear images 436 disgust images 4982 neutral images 7164 happy images 3993 angry images 3205 surprise images 4938 sad images
不難看出,除了“厭惡”的表情,其他每種表情的數(shù)量基本是平衡的。
Keras的ImageDataGenerator類可以從路徑中提供批量數(shù)據(jù):
from keras.preprocessing.image import ImageDataGenerator # number of images to feed into the NN for every batch batch_size=128 datagen_train=ImageDataGenerator() datagen_validation=ImageDataGenerator() train_generator=datagen_train.flow_from_directory(base_path + "train", target_size=(pic_size,pic_size), color_mode="grayscale", batch_size=batch_size, class_mode='categorical', shuffle=True) validation_generator=datagen_validation.flow_from_directory(base_path + "validation", target_size=(pic_size,pic_size), color_mode="grayscale", batch_size=batch_size, class_mode='categorical', shuffle=False)
Found 28821 images belonging to 7 classes. Found 7066 images belonging to 7 classes.
訓(xùn)練集中共有28821張表情圖片;驗(yàn)證集中共有7066張表情圖片。值得一提的是,此處還可以在獲取圖像時(shí)執(zhí)行數(shù)據(jù)增強(qiáng)(比如隨機(jī)旋轉(zhuǎn)和尺度縮放等)。上文代碼中函數(shù)flow_from_directory()用于指定生成器以何種方式導(dǎo)入圖像(路徑,圖像大小,顏色等)。
先來定義我們的CNN網(wǎng)絡(luò)架構(gòu):
from keras.layers import Dense, Input, Dropout, GlobalAveragePooling2D, Flatten, Conv2D, BatchNormalization, Activation, MaxPooling2D from keras.models import Model, Sequential from keras.optimizers import Adam # number of possible label values nb_classes=7 # Initialising the CNN model=Sequential() # 1 - Convolution model.add(Conv2D(64,(3,3), padding='same', input_shape=(48, 48,1))) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # 2nd Convolution layer model.add(Conv2D(128,(5,5), padding='same')) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # 3rd Convolution layer model.add(Conv2D(512,(3,3), padding='same')) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # 4th Convolution layer model.add(Conv2D(512,(3,3), padding='same')) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # Flattening model.add(Flatten()) # Fully connected layer 1st layer model.add(Dense(256)) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) # Fully connected layer 2nd layer model.add(Dense(512)) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) model.add(Dense(nb_classes, activation='softmax')) opt=Adam(lr=0.0001) model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
我們的CNN中包含4個(gè)卷積層和2個(gè)全連接層,卷積層負(fù)責(zé)從圖像中提取相關(guān)特征,全連接層用于對(duì)圖像進(jìn)行分類。我們使用ReLU函數(shù)在CNN中引入非線性,并使用BN(批量標(biāo)準(zhǔn)化)來提高網(wǎng)絡(luò)性能。此外,通過Dropout來減少過擬合。我們選用交叉熵作為損失函數(shù),激活函數(shù)選用常用于多分類任務(wù)的Softmax函數(shù)。
現(xiàn)在我們已經(jīng)定義了CNN,讓我們正式開始訓(xùn)練吧!
訓(xùn)練模型
# number of epochs to train the NN epochs=50 from keras.callbacks import ModelCheckpoint checkpoint=ModelCheckpoint("model_weights.h5", monitor='val_acc', verbose=1, save_best_only=True, mode='max') callbacks_list=[checkpoint] history=model.fit_generator(generator=train_generator, steps_per_epoch=train_generator.n//train_generator.batch_size, epochs=epochs, validation_data=validation_generator, validation_steps=validation_generator.n//validation_generator.batch_size, callbacks=callbacks_list)
Epoch 1/50 225/225 [==============================] - 36s 161ms/step - loss: 2.0174 - acc: 0.2333 - val_loss: 1.7391 - val_acc: 0.2966 Epoch 00001: val_acc improved from -inf to 0.29659, saving model to model_weights.h5 Epoch 2/50 225/225 [==============================] - 31s 138ms/step - loss: 1.8401 - acc: 0.2873 - val_loss: 1.7091 - val_acc: 0.3311 Epoch 00002: val_acc improved from 0.29659 to 0.33108, saving model to model_weights.h5 ... Epoch 50/50 225/225 [==============================] - 30s 132ms/step - loss: 0.6723 - acc: 0.7499 - val_loss: 1.1159 - val_acc: 0.6384 Epoch 00050: val_acc did not improve from 0.65221
從迭代輸出中不難看出,我們的模型能夠達(dá)到的最高驗(yàn)證準(zhǔn)確度為65%,這可能并不算高,但對(duì)于多分類任務(wù)來說,已經(jīng)相當(dāng)不錯(cuò)了。
我們將CNN的結(jié)構(gòu)保存到文件中:
# serialize model structure to JSON model_json=model.to_json() with open("model.json", "w") as json_file: json_file.write(model_json)
我們通過訓(xùn)練過程中保存的數(shù)據(jù)來繪制訓(xùn)練集和驗(yàn)證集的損失和準(zhǔn)確度演變曲線:
# plot the evolution of Loss and Acuracy on the train and validation sets import matplotlib.pyplot as plt plt.figure(figsize=(20,10)) plt.subplot(1, 2, 1) plt.suptitle('Optimizer : Adam', fontsize=10) plt.ylabel('Loss', fontsize=16) plt.plot(history.history['loss'], label='Training Loss') plt.plot(history.history['val_loss'], label='Validation Loss') plt.legend(loc='upper right') plt.subplot(1, 2, 2) plt.ylabel('Accuracy', fontsize=16) plt.plot(history.history['acc'], label='Training Accuracy') plt.plot(history.history['val_acc'], label='Validation Accuracy') plt.legend(loc='lower right') plt.show()
隨著訓(xùn)練的迭代次數(shù)增加,損失和準(zhǔn)確度的演變
除了損失和準(zhǔn)確度演變曲線,我們還可以通過繪制混淆矩陣來幫助我們了解我們的模型是如何對(duì)圖像進(jìn)行分類的:
# show the confusion matrix of our predictions # compute predictions predictions=model.predict_generator(generator=validation_generator) y_pred=[np.argmax(probas) for probas in predictions] y_test=validation_generator.classes class_names=validation_generator.class_indices.keys() from sklearn.metrics import confusion_matrix import itertools def plot_confusion_matrix(cm, classes, title='Confusion matrix', cmap=plt.cm.Blues): cm=cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] plt.figure(figsize=(10,10)) plt.imshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) plt.colorbar() tick_marks=np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=45) plt.yticks(tick_marks, classes) fmt='.2f' thresh=cm.max() / 2. for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.ylabel('True label') plt.xlabel('Predicted label') plt.tight_layout() # compute confusion matrix cnf_matrix=confusion_matrix(y_test, y_pred) np.set_printoptions(precision=2) # plot normalized confusion matrix plt.figure() plot_confusion_matrix(cnf_matrix, classes=class_names, title='Normalized confusion matrix') plt.show()
從混淆矩陣的結(jié)果來看,我們的模型在預(yù)測(cè)“高興”和“驚訝”的表情時(shí)表現(xiàn)非常優(yōu)秀,但是在預(yù)測(cè)“恐懼”的表情時(shí)則比較頭疼,因?yàn)槿菀缀汀氨瘋钡谋砬橄嗷煜?/p>
不管怎樣,隨著研究進(jìn)一步深入以及更廣泛的資源獲取,模型性能肯定能得到優(yōu)化和改善。下面,是時(shí)候在真實(shí)場(chǎng)景下檢測(cè)我們的模型性能了。我們將使用Flask,以便通過網(wǎng)絡(luò)攝像頭的視頻輸入進(jìn)行表情的實(shí)時(shí)檢測(cè)。
首先我們先創(chuàng)建一個(gè)類,它將為我們提供先前訓(xùn)練模型的預(yù)測(cè):
from keras.models import model_from_json import numpy as np class FacialExpressionModel(object): EMOTIONS_LIST=["Angry", "Disgust", "Fear", "Happy", "Neutral", "Sad", "Surprise"] def __init__(self, model_json_file, model_weights_file): # load model from JSON file with open(model_json_file, "r") as json_file: loaded_model_json=json_file.read() self.loaded_model=model_from_json(loaded_model_json) # load weights into the new model self.loaded_model.load_weights(model_weights_file) self.loaded_model._make_predict_function() def predict_emotion(self, img): self.preds=self.loaded_model.predict(img) return FacialExpressionModel.EMOTIONS_LIST[np.argmax(self.preds)]
接下來我們將實(shí)現(xiàn)一個(gè)能夠執(zhí)行以下操作的類:
1) 從網(wǎng)絡(luò)攝像頭獲取圖像流
2) 使用OpenCV檢測(cè)并框出人臉
3) 從我們的CNN網(wǎng)絡(luò)獲取預(yù)測(cè)結(jié)果并將預(yù)測(cè)標(biāo)簽添加到網(wǎng)絡(luò)攝像頭的圖像流中
4) 返回處理后的圖像流
import cv2 from model import FacialExpressionModel import numpy as np facec=cv2.CascadeClassifier('haarcascade_frontalface_default.xml') model=FacialExpressionModel("model.json", "model_weights.h5") font=cv2.FONT_HERSHEY_SIMPLEX class VideoCamera(object): def __init__(self): self.video=cv2.VideoCapture(0) def __del__(self): self.video.release() # returns camera frames along with bounding boxes and predictions def get_frame(self): _, fr=self.video.read() gray_fr=cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY) faces=facec.detectMultiScale(gray_fr, 1.3, 5) for (x, y, w, h) in faces: fc=gray_fr[y:y+h, x:x+w] roi=cv2.resize(fc, (48, 48)) pred=model.predict_emotion(roi[np.newaxis, :, :, np.newaxis]) cv2.putText(fr, pred, (x, y), font, 1, (255, 255, 0), 2) cv2.rectangle(fr,(x,y),(x+w,y+h),(255,0,0),2) _, jpeg=cv2.imencode('.jpg', fr) return jpeg.tobytes()
你以為這就完了?
還沒,我們將創(chuàng)建一個(gè)Flask應(yīng)用程序,將我們的表情預(yù)測(cè)結(jié)果呈現(xiàn)到網(wǎng)頁中。
from flask import Flask, render_template, Response from camera import VideoCamera app=Flask(__name__) @app.route('/') def index(): return render_template('index.html') def gen(camera): while True: frame=camera.get_frame() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/video_feed') def video_feed(): return Response(gen(VideoCamera()), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__=='__main__': app.run(host='0.0.0.0', debug=True)
激動(dòng)人心的時(shí)刻到了,下面讓我們一起看看最終的檢測(cè)效果吧!
學(xué)會(huì)它,你就又習(xí)得一項(xiàng)實(shí)(shua)用(shuai)新技能。下次群聊發(fā)啥表情包,直接甩個(gè)表情識(shí)別網(wǎng)頁程序過去,分分鐘實(shí)力carry秒殺全場(chǎng)。你就是人群中最靚的仔!
留言 點(diǎn)贊 關(guān)注
我們一起分享AI學(xué)習(xí)與發(fā)展的干貨
歡迎關(guān)注全平臺(tái)AI垂類自媒體 “讀芯術(shù)”
年來,圖像識(shí)別研究的精確度越來越高,其中“手寫數(shù)字識(shí)別”作為圖像識(shí)別中的一個(gè)經(jīng)典問題,通過“卷積神經(jīng)網(wǎng)絡(luò)(CNN)”的方式,某些解決方案的精確度更是達(dá)到了99.1%。大家在網(wǎng)上也能搜索到相應(yīng)的實(shí)現(xiàn)教程,但是大部分教程都比較簡(jiǎn)略,缺乏深入淺出的講解,讓初學(xué)者們難以上手。
而且常見的“手寫數(shù)字識(shí)別”教程往往是僅僅介紹已有的公共數(shù)據(jù)里的樣本數(shù)字的識(shí)別方法,這就和實(shí)際應(yīng)用中的“識(shí)別自己提供的手寫數(shù)字”差距很大。考慮到這些gap,本文就詳細(xì)給大家介紹一個(gè)更加貼近“實(shí)戰(zhàn)”的、更詳細(xì)的教程:如何用Keras構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)識(shí)別“自己”的手寫字。
圖1:手寫字識(shí)別示圖
使用的編程語言:Python。
使用的依賴包/框架:TensorFlow,Keras。
使用的模型/方法:卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network,即CNN)。
使用的數(shù)據(jù)集:MNIST數(shù)據(jù)集--28x28像素的灰度手寫數(shù)字圖片--包括60000個(gè)訓(xùn)練樣本和10000個(gè)測(cè)試樣本(該MNIST數(shù)據(jù)集為事先處理好的“一個(gè)數(shù)字一張圖”的標(biāo)準(zhǔn)數(shù)據(jù)集,背景為純黑色、即byte值為0,數(shù)字筆劃為白色,即筆劃的最高值為255)。另有自行上傳的手寫字體圖片約共30個(gè)。
解決的問題/實(shí)現(xiàn)的功能:
1,基于MNIST數(shù)據(jù)集,訓(xùn)練一個(gè)能識(shí)別手寫阿拉伯?dāng)?shù)字的模型,即能夠?qū)⑤斎氲氖謱憯?shù)字的圖和對(duì)應(yīng)的阿拉伯?dāng)?shù)字進(jìn)行匹配(識(shí)別)。
2,用戶將自己創(chuàng)建的手寫數(shù)字作為一個(gè)圖片、上傳至訓(xùn)練好的模型中做預(yù)測(cè),讓模型識(shí)別出對(duì)應(yīng)的數(shù)字。
推薦使用的平臺(tái):達(dá)仁云主機(jī)【Linux + JupyterLab】公共鏡像。
圖2:達(dá)仁云主機(jī)示圖
可以看到筆者推薦使用“達(dá)仁云主機(jī)”這個(gè)工具(來自于atlas.daren.io)來進(jìn)行學(xué)習(xí)和練習(xí),這是因?yàn)閷?duì)于第一次試用CNN、TensorFlow或Keras的同學(xué)來說,往往不僅僅缺乏必要的編程和軟件配置知識(shí),也經(jīng)常缺少合適的硬件主機(jī),例如合適的GPU卡。這樣很多同學(xué)一開始上手時(shí)需要投入的時(shí)間和預(yù)算成本就非常高,相當(dāng)于一個(gè)和我們要學(xué)習(xí)的CNN基本知識(shí)和應(yīng)用并不是密切相關(guān)、不必要的“高門檻”。
使用類似于“達(dá)仁云主機(jī)”這樣的產(chǎn)品可以大大降低同學(xué)們一開始上手的難度。雖然同樣是采用云上租用虛擬機(jī)的方式使用,“達(dá)仁云主機(jī)”的特殊之處在于是“立即可用”的“預(yù)設(shè)+托管”型云主機(jī)(managed cloud PC):“達(dá)仁云主機(jī)”是預(yù)先安裝好基礎(chǔ)軟件(例如這里會(huì)用到的JupyterLab)、配置好軟件和網(wǎng)絡(luò)設(shè)置(例如立即可以在瀏覽器里直接登錄訪問這個(gè)云主機(jī)上的JupyterLab)、并且“自動(dòng)化+智能”處理好鏡像存儲(chǔ)和數(shù)據(jù)持久化等一些云主機(jī)的常見問題。
用“達(dá)仁云主機(jī)”這種瀏覽器中立即可用的“預(yù)設(shè)+托管”型云主機(jī)來做CNN的學(xué)習(xí)和練習(xí),就會(huì)更加容易上手、直接進(jìn)入CNN知識(shí)和技能學(xué)習(xí)的“核心區(qū)”。
基于達(dá)仁云主機(jī)這樣的簡(jiǎn)易設(shè)定,我們?cè)诰W(wǎng)頁上僅需不斷點(diǎn)擊“下一步”,就能啟動(dòng)一臺(tái)所需環(huán)境和配置的云主機(jī)。“達(dá)仁云主機(jī)”其實(shí)就是把平時(shí)需要“看懂一整本教程書”以后才能用起來的“云主機(jī)”的那些復(fù)雜的設(shè)置和維護(hù)“智能化/傻瓜化”,讓用戶僅需點(diǎn)擊幾個(gè)按鈕,就能在瀏覽器里直接啟動(dòng)一臺(tái)“立即能用”的云主機(jī)。
特別方便的是“達(dá)仁云主機(jī)”通過一個(gè)普通瀏覽器即可訪問,不需要安裝任何軟件或購買任何硬件。云主機(jī)啟動(dòng)后是按秒計(jì)費(fèi),停機(jī)就立刻停止計(jì)費(fèi),沒有“包月”的門檻,“省心省錢”。“達(dá)仁云主機(jī)”更有百余種云主機(jī)配置可選,其中就包括很多款適合做CNN機(jī)器學(xué)習(xí)使用的、帶GPU卡的云主機(jī)類型。
這些特色就讓很多因?yàn)闆]有預(yù)算(適合做AI的GPU卡現(xiàn)在可是幾千元甚至上萬元一張)、或者被各種云計(jì)算教科書“望而卻步”過的同學(xué)能夠“省心省事”地立即開始用上合適的AI學(xué)習(xí)環(huán)境。
注意了,這個(gè)達(dá)仁云主機(jī)提供的開發(fā)環(huán)境和計(jì)算資源,是真正可以做開發(fā)、做項(xiàng)目的“實(shí)戰(zhàn)”級(jí)環(huán)境,可不是一些常見的“只能做作業(yè)”的“假”的模擬開發(fā)環(huán)境哦~
好了,我們開始進(jìn)入正題,筆者將本教程分為三部分
一、達(dá)仁云主機(jī)三分鐘開啟環(huán)境篇
1.1、創(chuàng)建虛擬硬盤;
1.2、選擇公共鏡像;
1.3、配置JupyterLab云主機(jī);
1.4、從終端配置環(huán)境。
二、建模型篇:模型訓(xùn)練與評(píng)估
2.1、導(dǎo)入所需的依賴包與框架
2.2、如何對(duì)數(shù)據(jù)預(yù)處理;
2.3、如何訓(xùn)練模型;
2.4、如何評(píng)估模型。
三、用模型篇:使用模型識(shí)別輸入的手寫字體
3.1、嘗試識(shí)別在便箋上寫的數(shù)字;
3.2、嘗試識(shí)別白紙作為背景的手寫數(shù)字;
3.3、嘗試識(shí)別手寫字體網(wǎng)站截取的手寫數(shù)字;
3.4、嘗試識(shí)別在Atlas OS筆記功能里手寫的數(shù)字。
注意:本教程涉及的數(shù)據(jù)、Python代碼、對(duì)應(yīng)結(jié)果,都在本文的圖文教程中全部提供,并可以在https://gitee.com/diagnoa/public/tree/master/tutorial/CNN-general-tutorial-01下載到。
一、達(dá)仁云主機(jī)三分鐘開啟環(huán)境篇
1.1、創(chuàng)建虛擬硬盤
在瀏覽器中登錄Atlas OS(atlas.daren.io),選擇左側(cè)導(dǎo)航欄中的達(dá)仁云主機(jī),在達(dá)仁云主機(jī)界面創(chuàng)建虛擬硬盤,使用此硬盤作為主要的數(shù)據(jù)和運(yùn)行目錄。
圖1. 啟動(dòng)云主機(jī)界面
1.2、選擇公共鏡像
達(dá)仁云主機(jī)為用戶“預(yù)設(shè)配置好”的JupyterLab、RStudio、Eclipse等多種開發(fā)環(huán)境及Windows、Linux遠(yuǎn)程桌面,這里我們選擇Linux + JupyterLab鏡像。
圖2.選擇主機(jī)鏡像界面
1.3、配置JupyterLab云主機(jī)
點(diǎn)擊啟動(dòng)云主機(jī)后,我們依次選擇GPU類型的云主機(jī)g4dn.xlarge,設(shè)置虛擬硬盤大小,設(shè)置合適的內(nèi)存,為云主機(jī)命名,然后點(diǎn)擊啟動(dòng)。
圖3. 選擇配置GPU實(shí)例界面
達(dá)仁云主機(jī)提供百余種配置可選(CPU : 1~96核、內(nèi)存:0.5GB~3TB、硬盤:1GB~16TB),費(fèi)用低至3分錢/小時(shí)起,可以隨時(shí)開啟和關(guān)閉。當(dāng)云主機(jī)狀態(tài)由“啟動(dòng)中”變?yōu)椤斑\(yùn)行中”時(shí),便可在啟動(dòng)JupyterLab后進(jìn)行后續(xù)操作。此教程提供從IP啟動(dòng)的例子。
圖4. 云主機(jī)啟動(dòng)中狀態(tài)界面
圖5. 云主機(jī)運(yùn)行中狀態(tài)界面
圖6. 使用IP啟動(dòng)云主機(jī)界面
此時(shí)瀏覽器會(huì)打開Jupyter的操作界面,輸入系統(tǒng)分配的初始密碼即可登陸。
圖7. 輸入密碼登陸Jupyter
1.4、打開終端配置環(huán)境
圖8. 使用終端界面
圖9. 終端界面
輸入密碼登錄后,在圖9界面中鍵入如下代碼安裝程序運(yùn)行所需環(huán)境
# 安裝必要的系統(tǒng)環(huán)境,即所依賴的系統(tǒng)程序和編譯工具
# 此鏡像默認(rèn)安裝了conda環(huán)境,所有的操作可以在base這個(gè)環(huán)境中進(jìn)行
sudo yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo yum update -y
sudo yum -y install kernel-devel-$(uname -r) kernel-headers-$(uname -r)
sudo yum -y install gcc gcc-c++
sudo yum install libXext.x86_64 libXrender.x86_64 libXtst.x86_64 mesa-libGL.x86_64 -y
# 下載并安裝GPU驅(qū)動(dòng)
cd DataDrive/
wget https://cn.download.nvidia.com/tesla/450.119.04/NVIDIA-Linux-x86_64-450.119.04.run
sudo sh NVIDIA-Linux-*.run
# 使用conda安裝Keras環(huán)境
conda install -c anaconda tensorflow-gpu keras matplotlib pillow -y
conda install -c conda-forge opencv -y
至此本次教程所需環(huán)境已經(jīng)配置完畢,我們就可以使用Jupyter Notebook開始執(zhí)行代碼。
圖10. 打開Jupyter Notebook界面
二、建模型篇:模型訓(xùn)練與評(píng)估
2.1、導(dǎo)入所需的依賴包與框架
# 在程序的開始,導(dǎo)入待使用的包
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.optimizers import Adam
from keras.utils import np_utils
from PIL import Image
import numpy as np
import os
from tensorflow import keras
import cv2
import matplotlib.pyplot as plt
2.2、如何對(duì)數(shù)據(jù)做預(yù)處理
# 加載數(shù)據(jù)
# 注意:一般模型訓(xùn)練需要區(qū)分訓(xùn)練數(shù)據(jù)(train)和測(cè)試數(shù)據(jù)(test),測(cè)試數(shù)據(jù)不可以在訓(xùn)練過程中使用,以便在訓(xùn)練過程結(jié)束以后,能夠用測(cè)試數(shù)據(jù)來評(píng)估所訓(xùn)練的模型的性能。
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 將輸入數(shù)據(jù)reshape成CNN期望的格式(也就是將圖像數(shù)據(jù)轉(zhuǎn)成神經(jīng)網(wǎng)絡(luò)能識(shí)別的數(shù)組數(shù)據(jù))
X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], X_train.shape[2], 1).astype('float32')
X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], X_test.shape[2], 1).astype('float32')
# 將輸入數(shù)據(jù)歸一化
# 注意1:一般CNN數(shù)據(jù)的歸一化(Normalization)是將數(shù)據(jù)轉(zhuǎn)化到[0, 1]這個(gè)區(qū)間里(把數(shù)值變小一些)。因?yàn)槿绻斎霐?shù)據(jù)里的數(shù)據(jù)值過大(例如幾百或上萬),將會(huì)造成模型訓(xùn)練時(shí)的時(shí)間過長(zhǎng)、輪數(shù)過多(造成這個(gè)現(xiàn)象的一個(gè)原因:一些小的初始化系數(shù)項(xiàng)需要經(jīng)過很多輪的訓(xùn)練才能“適應(yīng)”包含“大數(shù)值”的變量項(xiàng)),而且很有可能會(huì)導(dǎo)致訓(xùn)練失敗。所以一般所有的機(jī)器學(xué)習(xí)前,都需要對(duì)數(shù)據(jù)進(jìn)行預(yù)處理,例如歸一化或標(biāo)準(zhǔn)化。
# 注意2:數(shù)據(jù)的歸一化和標(biāo)準(zhǔn)化(Standardization)和中心化(Centering)是三種不同(但聯(lián)系緊密)的操作。此處使用的是歸一化。對(duì)于基本符合正態(tài)分布的數(shù)據(jù),建議使用標(biāo)準(zhǔn)化的預(yù)處理。
X_train /= 255
X_test /= 255
# 將輸出數(shù)據(jù)類別變?yōu)閛ne hot編碼 (one hot encoding)
# 為什么這里要做one hot編碼呢?因?yàn)樯窠?jīng)網(wǎng)絡(luò)無法識(shí)別常規(guī)的分類變量(categorical data)。感興趣的同學(xué)可以在這里看一看做one hot編碼的詳細(xì)背景和原因:https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/。
number_of_classes = 10
y_train = np_utils.to_categorical(y_train, number_of_classes)
y_test = np_utils.to_categorical(y_test, number_of_classes)
2.3、如何訓(xùn)練模型
# 創(chuàng)建模型
# 創(chuàng)建模型有時(shí)候可以說一種“藝術(shù)”,因?yàn)槟P偷倪x擇,例如各個(gè)層的參數(shù)選擇多種多樣,而模型中層與層之間的關(guān)系更是可以“千奇百怪”,這里僅僅提供了一種常見的適合于MNIST數(shù)據(jù)的網(wǎng)絡(luò)。感興趣的同學(xué)們可以閱讀Keras和PyTorch文檔里關(guān)于網(wǎng)絡(luò)中不同層的各種類型的作用和其配置參數(shù)影響的介紹,創(chuàng)建自己的網(wǎng)絡(luò)結(jié)構(gòu),來試一試:
# https://keras.io/api/layers/convolution_layers/
# https://pytorch.org/docs/stable/nn.html#convolution-layers
# 注:給一個(gè)“模型”嘗試不同結(jié)構(gòu)和不同參數(shù)(即常常提到的一個(gè)模型的“超參數(shù)”,hyperparameter)設(shè)置,找到最優(yōu)化的模型超參數(shù),往往需要嘗試成千上萬種潛在的模型結(jié)構(gòu)和配置,這也是為什么在機(jī)器學(xué)習(xí)實(shí)戰(zhàn)中,模型的創(chuàng)建和優(yōu)化是如此的消耗資源(在成千上萬個(gè)機(jī)器節(jié)點(diǎn)上跑不同的模型,或者在一個(gè)機(jī)器上跑成千上萬個(gè)不同的模型)。
num_classes = 10 # 代表0-9共10個(gè)數(shù)字,10種類別。
input_shape = (28, 28, 1) # 輸入數(shù)據(jù)shape為28x28x1。
model = Sequential(
[
keras.Input(shape=input_shape), # 定義輸入層,設(shè)置輸入層為與訓(xùn)練數(shù)據(jù)相同的維度。
Conv2D(32, kernel_size=(3, 3), activation="relu"), # 定義卷積層網(wǎng)絡(luò),本層需要學(xué)習(xí)32個(gè)卷積核,卷積核大小為3x3。激活函數(shù)為Relu。
MaxPooling2D(pool_size=(2, 2)), # 疊加池化層,池化窗口形狀為2×2的最大池化。
Conv2D(64, kernel_size=(3, 3), activation="relu"), # 疊加卷積層網(wǎng)絡(luò)。
MaxPooling2D(pool_size=(2, 2)), # 疊加池化層。
Flatten(), # 將輸入“壓平”,即把多維的輸入一維化,常用在從卷積層到全連接層的過渡。
Dropout(0.5),# Dropout將在訓(xùn)練過程中每次更新參數(shù)時(shí)按一定概率(0.5)隨機(jī)斷開輸入神經(jīng)元,可防止過擬合。
Dense(num_classes, activation="softmax"),# 全連接層,輸出層,激活函數(shù)為softmax。
]
)
# 打印模型信息
model.summary()
運(yùn)行上述代碼,輸出結(jié)果為:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 1600) 0
_________________________________________________________________
dropout (Dropout) (None, 1600) 0
_________________________________________________________________
dense (Dense) (None, 10) 16010
=================================================================
Total params: 34,826
Trainable params: 34,826
Non-trainable params: 0
___________________________________________________________
上述結(jié)果打印了模型的相關(guān)信息:從左至右依次為網(wǎng)絡(luò)每一層的信息、每一層的輸出結(jié)果的樣式、每一層的參數(shù)個(gè)數(shù)。打印這些信息可以幫助我們更直觀地了解所構(gòu)建模型的結(jié)構(gòu)。
# 訓(xùn)練模型
# 注:一般訓(xùn)練模型是最消耗時(shí)間的步驟,這里可能會(huì)需要等一段時(shí)間
batch_size = 128 # 設(shè)置batch size
epochs = 15 # 設(shè)置epoch。
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
# 模型的loss選擇categorical_crossentropy, 優(yōu)化器選擇adam,metrics選擇accuracy。
model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1) # 用訓(xùn)練數(shù)據(jù)訓(xùn)練模型,并按照0.1的比例抽取數(shù)據(jù)進(jìn)行validation。
運(yùn)行上述代碼,輸出結(jié)果省略中間部分,展示如下:
Epoch 1/15
422/422 [==============================] - 6s 14ms/step - loss: 0.3649 - accuracy: 0.8872 - val_loss: 0.0844 - val_accuracy: 0.9782
Epoch 2/15
422/422 [==============================] - 2s 4ms/step - loss: 0.1099 - accuracy: 0.9660 - val_loss: 0.0556 - val_accuracy: 0.9848
......
Epoch 15/15
422/422 [==============================] - 1s 4ms/step - loss: 0.0335 - accuracy: 0.9890 - val_loss: 0.0286 - val_accuracy: 0.9915
上述結(jié)果打印了模型訓(xùn)練過程中l(wèi)oss的變化。在模型訓(xùn)練時(shí),選擇了categorical cross entropy作為loss,來衡量原始數(shù)字類別和由模型預(yù)測(cè)的數(shù)字類別的差異。loss值越小,說明預(yù)測(cè)結(jié)果與原始結(jié)果越相似。打印結(jié)果中l(wèi)oss是訓(xùn)練過程產(chǎn)生的,val_loss是驗(yàn)證過程產(chǎn)生的,val_accuracy是指validation過程中的準(zhǔn)確性。計(jì)算的準(zhǔn)確性越高效果越好。
2.4、如何評(píng)估模型
# 用測(cè)試數(shù)據(jù)評(píng)估模型
score = model.evaluate(X_test, y_test, verbose=0) # 用測(cè)試數(shù)據(jù)評(píng)估模型,不輸出中間過程
print("Test loss:", score[0]) # 打印loss值
print("Test accuracy:", score[1]) # 打印accuracy
# 運(yùn)行上述代碼,輸出結(jié)果為:
Test loss: 0.027751104906201363 # 測(cè)試數(shù)據(jù)的loss
Test accuracy: 0.991100013256073# 測(cè)試數(shù)據(jù)類別的準(zhǔn)確性達(dá)到99.1%
所以如果僅僅拿MNIST數(shù)據(jù)集里數(shù)據(jù)做評(píng)估的話,那么這個(gè)模型的準(zhǔn)確性相當(dāng)?shù)母撸_(dá)到了99.1%。但是如果拿來“實(shí)用”一下呢?我們來看看這個(gè)模型能不能識(shí)別我們自己手寫的數(shù)字。
三、用模型篇:使用模型識(shí)別輸入的手寫字體
生活中的事一般都是“理想很豐滿,現(xiàn)實(shí)很骨感”,真的要讓一個(gè)模型把一個(gè)手寫的數(shù)字給識(shí)別出來,其實(shí)還真不是那么容易的。我們一起來看一下吧:
3.1、嘗試識(shí)別在便箋上寫的數(shù)字
我們先試一試“隨便”地在便簽紙上寫一個(gè)簡(jiǎn)單的數(shù)字,讓這個(gè)模型來試一下吧。在一張最普通最常見的(就是淺黃色的那種)便箋上寫一個(gè)數(shù)字(如我們圖中的這個(gè)“扭曲的0”),然后拍照后存到電腦(或云主機(jī))里,先試一下吧。
注:讓模型識(shí)別一個(gè)普通圖像里的數(shù)字可不是那么“簡(jiǎn)單/直接”的,需要很多個(gè)“把一般的彩色照片圖像轉(zhuǎn)換成模型可以讀取的數(shù)組”的操作步驟。例如下面這整整15行的代碼就是做這個(gè)的:
pic = '/home/diagnoa/DataDrive/WechatIMG1.jpeg' # 手寫字原始圖片
img = Image.open(pic) # 讀取圖片文件
ax = plt.subplot(1, 2, 1) # 選擇畫布1行2列區(qū)域的左邊繪圖
plt.imshow(img) # 在左邊繪制原始手寫圖片
plt.gray() # 繪制灰度圖
ax.get_xaxis().set_visible(False) # 隱藏X軸
ax.get_yaxis().set_visible(False) # 隱藏Y軸
ax = plt.subplot(1, 2, 2) # 選擇畫布1行2列區(qū)域的右邊繪圖
target_shape = (28,28) # 設(shè)置數(shù)據(jù)shape
img2 = cv2.imread(pic, cv2.IMREAD_GRAYSCALE) # 讀取圖片為灰度圖
img2 = cv2.resize(img2, target_shape) # resize圖片
plt.imshow(img2, cmap='gray') # 繪制灰度圖
ax.get_xaxis().set_visible(False) # 隱藏X軸
ax.get_yaxis().set_visible(False) # 隱藏Y軸
plt.show() # 畫圖
因?yàn)镸NIST訓(xùn)練的模型要求的輸入圖片是(28x28x1)的灰度圖,且數(shù)值是在0-1之間并且背景反轉(zhuǎn)的(即背景為黑色,byte值為0,筆劃信號(hào)為正值,這樣在轉(zhuǎn)化出的數(shù)組中方便直觀觀察)。此處我們使用的手寫數(shù)字的照片在經(jīng)過了上述的預(yù)處理之后,我們并不確定還有多少有效信息得到了保留。因此為了能夠盡可能地對(duì)比原始圖片和輸入模型的圖片,上述代碼對(duì)預(yù)處理之后的圖片做了可視化,即上面的這一部分代碼中的使用到plt函數(shù)的這些行。
注:此處做預(yù)處理的代碼參考的網(wǎng)絡(luò)資料來源:
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。