整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          手套Talking Hands可以記錄手部動作并轉換

          手套Talking Hands可以記錄手部動作并轉換為文字信息

          章相關引用及參考:映維網

          記錄手部動作并將其轉換為文字

          映維網 2018年04月19日)意大利初創公司Limix開發了一種名為Talking Hands的手套,其可以記錄手部動作并將其轉換為文字,轉發至智能手機設備,然后再通過語音合成器進行播放。他們希望以這種方式來彌合大多數聾障人士所面臨的通信障礙。

          Limix的創始人Francesco Pezzuoli說道:“Talking Hands不僅可以翻譯每一個字母,而且它的可定制程度非常高:用戶可以記錄他/她的手語,然后Talking Hands就會翻譯它們。這是一種可穿戴設備,不需要任何外部攝像頭或計算機,因此用戶隨時隨地都可以使用它。”

          該項目始于一年前,當時是作為Limix,意大利國家聾人協會(ENS),以及專門教導聾啞學生的意大利公立高中I.S.I.S.S. Magarotto之間的合作產物。然而,人們告訴Pezzuoli和另一位聯合創始人Dario Corona說這一概念不會成功,因為設備無法測量細微的手指動作。但他們堅持不懈,并最終研發出可行的技術。現在,他們正準備在2018年6月推出第一個工業原型。

          他們的概念成為了今年The Chivas Venture競賽的最終入圍項目之一,并有機會競逐100萬美元的投資。在今年5月,最終入選者將乘飛機前往阿姆斯特丹參加最終的決賽。屆時他們將有五分鐘時間向專家評審團推銷他們的項目。對于The Chivas Venture的風投,開發團隊希望這可以為工業原型的生產和擴展提供資金支持。

          Pezzuoli解釋說:“主要的問題是,非手語者通常不太了解手語。他們可能甚至沒有意識到美國手語(和其他手語,如英國手語和中國手語)是非常不同的語言,其有著自己的語法和措辭,而不是口頭語言的單詞重述。”

          Talking Hands能夠繞開這個問題,因為其允許每個用戶通過應用程序創建和自定義他們自己的手語,并將其直接鏈接到智能手機。他們可以創建專用于不同情況的字典,例如在醫療緊急情況下需要與醫生溝通的常用詞語。

          Pezzuoli聲稱:“從來沒有人能夠發現和實現像我們這樣簡單,低成本和有用的解決方案。Talking Hands的首次生產成本約為500歐元,包含一切,因此與市場上的其他手套相比,它的價格相對較低。”

          具體操作:

          • 用戶將Talking Hands應用下載到移動設備上。

          • 用戶將應用的口頭語言設置為英語和意大利語等語言,將其作為手語識別的輸出語言。

          • 然后,用戶可以在穿戴手套時錄制手語,然后系統會將其與字母,單詞或整個短語相關聯。

          • 每當用戶重復該手語時,智能手機都會代表用戶說出相應的詞語。

          • Talking Hands可以翻譯世界各地使用的幾種不同手語:ASL(美國手語),BSL(英國手語),CSL(中國手語)等等。

          • Talking Hands同時可以與增強現實系統進行交互,從而進行員工培訓,與虛擬博物館和游戲控制器交互。

          意大利國立聾人高等教育研究所(National Institute for Higher Education of Deaf People)的Rita Antoniozzi教授解釋說:“Talking Hands可以幫助聾啞人擺脫沉默,使他們能夠與不懂手語的人進行第一范式的溝通。”她認為,這項技術將能為失聰用戶提供支持,使他們能夠實現更大程度的獨立性和平等性。

          但對Pezzuoli而言,平等性的好處在很大程度上是雙向的:“我想證明技術可以成為統一和悅人的力量,使人成為中心,這樣我們就可以創建并擴大這種關系,納入殘疾人,并與他們的世界和文化融合在一起。”他補充說,殘疾人士看待世界的不同方式實際上是一項重要資產,它可以帶來創造性思維和創新,因此賦予他們“聲音”不僅對聾人社區有好處,其對整個社會都有很大的益處。

          原文鏈接:https://yivian.com/news/44228.html

          文共4732字,預計學習時長15分鐘


          現在的年輕人聊起天來都是一場場你來我往的表情包大戰。稍有不慎,就會立馬敗下陣來。

          你可能擁有數G個表情包存圖,但總是苦于表情包太多太亂,每次挑選都是曠日持久。等好不容易終于選中一張滿意的表情包,卻發現對方早已切到下一回合。



          要是有個功能可以把表情包一鍵分類就好了。這可能,會隨著FER(面部表情識別技術)的發展成為現實。


          表情識別vs人臉識別


          面部表情識別技術源于1971年心理學家Ekman和Friesen的一項研究,他們提出人類主要有六種基本情感,每種情感以唯一的表情來反映當時的心理活動,這六種情感分別是憤怒(anger)、高興(happiness)、悲傷 (sadness)、驚訝(surprise)、厭惡(disgust)和恐懼(fear)。

          盡管人類的情感維度和表情復雜度遠不是數字6可以量化的,但總體而言,這6種也差不多夠描述了。



          事實上,表情識別技術差不多可以算是在人臉識別技術的基礎上發展而來的。因此,表情識別也需要依賴于人臉的特征點檢測。


          所謂的特征點,就是預先定義的一組臉部或五官輪廓的點。在人臉特征點檢測中,通常我們比較關注的特征點一般位于眉毛、眼睛、嘴巴的位置,而鼻子在各種表情中的位置變化較不明顯,因此很多研究中都忽略對鼻子位置的特征點進行檢測。


          圖片來源:shutterlock


          但兩者還是有區別的,表情識別從技術上來說還是比人臉識別要更加復雜。人臉識別是一個靜態識別問題,最經典的人臉識別案例就是輸入兩張人臉照片,然后讓機器去判定兩張臉是不是屬于同一個人。而表情識別是給定一個人臉的連續動作幀,是一個時間段內表情變化的動態判定問題。

          人臉識別實際上是個去表情的過程,不管作出什么表情,不管是哭還是笑,都要想辦法去識別為同一個人。然而表情識別卻是放大表情的過程,對于同一個人,通過觀察表情變化來推斷其情緒的起伏。


          圖片來源:shutterlock


          相比于人臉識別,表情識別的動態不確定性成分更大,不僅需要做到精確,而且需要做到實時。如果憤怒被檢測為悲傷,或者當前檢測的表情已經是三秒前的表情狀態了,那肯定都是沒有辦法滿足實際應用需求的。

          說到應用,人臉識別最常見的應用場景可能要數“身份驗證”,而表情識別除了我們上面提到的能進行表情分類外,還可以廣泛應用于多個領域。

          比如用于電影制作,往后不再需要設計動畫,只需要將真人的表情動作直接映射即可。用于產品投放前的反響測試,則可以通過分析被試者的表情來預測用戶體驗。用于公安的審問環節,可以通過觀察受審者的細微表情變化來幫助判斷其證詞是否屬實。當然,在未來,如果機器能夠通過識別我們的表情來為我們提供個性化的服務,就能實現更好的人機交互。



          圖中右下角顯示原始表情,根據表情來進行四川變臉。


          當表情識別遇上深度學習


          目前,深度學習已強勢滲透進各個學科各個領域,大數據已成為這個時代最標志的特征之一。要用深度學習來做表情識別,第一步自然是選用一個數據豐富的表情庫,目前比較常用的表情庫主要有FER2013人臉數據集、日本ATR技術研究所建立的JAFFE日本女性表情數據庫以及美國CMU機器人研究所和心理學系共同建立的CKACFEID人臉表情數據庫。


          JAFFE日本女性表情數據庫


          總體來說,基于深度學習的表情識別一般分為以下幾個步驟:


          1)圖像獲取:通過攝像頭等來獲得圖像輸入。


          2)圖像預處理:對圖像中人臉識別子區域進行檢測,從而分割出人臉并去掉背景和無關區域。然后,進一步對圖像中的人臉進行標定。目前IntraFace是最常用的人臉標定方法,通過使用級聯人臉關鍵特征點定位(SDM),可準確預測49個關鍵點。為了保證數據足夠充分,可以采用旋轉、翻轉、縮放等圖像增強操作,甚至可以利用現在大火的GAN來輔助生成更多的訓練數據。

          至此,準備工作可還沒完事。由于圖像中不同光照強度和頭部姿態對表情識別的效果影響巨大,所以在開始正式工作前,還需要對光照和姿態做歸一化處理。不必擔心,站在巨人肩膀上的我們有很多現成的歸一化方法,比如使用INFace工具箱對光照進行歸一化,以及使用FF-GAN,TP-GAN,DR-GAN這些基于GAN的深度模型來矯正面部姿態從而生成正面人臉。


          基于深度學習的面部表情識別系統


          3)特征學習深度網絡

          傳統表情識別技術和深度表情識別技術最大的區別就在于特征學習的方式不同。傳統表情識別技術的特征提取方法主要有Gabor小波變換、局部二值模式(LBP)、局部線性嵌入(LLE)、梯度方向直方圖(HOG)等。

          近些年來,有越來越多的深度網絡被用于FER,其中包括深度置信網絡DBN、遞歸神經網絡RNN以及卷積神經網絡CNN等。

          以CNN為例,面部表情識別的CNN框架如下圖所示,與經典的卷積神經網絡無甚差別,主要也是包含輸入層、卷積層、全連接層和輸出層。


          面部表情識別CNN架構(改編自 埃因霍芬理工大學PARsE結構圖)


          其中,通過卷積操作來創建特征映射,將卷積核挨個與圖像進行卷積,從而創建一組要素圖,并在其后通過池化(pooling)操作來降維。



          CNN表情識別網絡中使用卷積和最大池化操作


          通常,在致密層(又稱為全連接層)的末端可以加上損失層,目的是修正正反向的傳播誤差,此后網絡輸出的直接就是每個輸入樣本的表情分類預測概率。當提供的數據越多,網絡可以逐步進行微調,直至損失最小。看起來好像我們設置的網絡節點越多,模型的表達能力就會越好,但這也同時會導致訓練數據容易陷入過擬合狀態。一般使用Dropout來解決過擬合問題,該方法不僅可以保證模型在訓練期間的敏感性也可以保持框架的必要復雜度。


          神經網絡訓練:前向傳播(左)和后向傳播(右)


          輸出層常用Sigmoid或者Softmax作為激活函數,通過激活函數將神經元的輸入映射到輸出端。實際上,激活函數并不是要激活什么,而是需要把激活的神經元特征保留并映射出來,其他的數據屬于冗余就被剔掉了。在輸出層我們就能直接得到每個表情所屬的情緒類別及相應概率。


          盡管這看起來并不難,但表情識別除面臨光照變化、非正面頭部姿態等帶來的挑戰之外,對低強度的表情識別也較為困難;并且,理想的表情數據庫應該包含各個種族、各個年齡階段的各種表情,除了數據獲取的難度外,對大量復雜自然場景下的人臉進行精準標注也是一大難點。但隨著數據的豐富和算法的改進,這些都將不會是什么大問題。


          表情識別太高端?不,你也可以!


          下面,我們將通過實例教你如何實現表情識別。


          首先,請確保你的電腦上已經安裝和配置好Keras、Flask和OpenCV。


          然后,選擇一個合適的表情庫,在這個實例中,我們選擇FER2013表情庫。

          這個數據集中大約包含36000張大小為48*48像素的灰度圖像,并且都已自動調整過,基本每張人臉在圖像中的位置和所占比例都差不多。除了心理學家Ekman和Friesen提出的6種情緒外,這里加入了一種新的情緒—中性(neutral)。每種情緒對應一個數字類別,0=Angry(憤怒), 1=Disgust(厭惡), 2=Fear(恐懼), 3=Happy(高興), 4=Sad(悲傷), 5=Surprise(驚訝), 6=Neutral(中性)。

          現在,正式工作開始。


          原始數據由圖像每個像素灰度值的數組數據組成,我們將數據轉換為原始圖像并將其拆分放進多個子文件中。其中,80%的數據放進訓練集中,剩余20%的數據用于測試。

          images/
           train/
           angry/
           disgust/
           fear/
           happy/
           neutral/
           sad/
           surprise/
           validation/
           angry/
           disgust/
           fear/
           happy/
           neutral/
           sad/
           surprise/
          


          快速數據可視化


          首先讓我們看看我們的圖像長什么樣子:

          # 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()
          


          部分訓練樣本


          你能猜出這些圖像對應的表情么?


          這對人類來說可能非常簡單,但對于機器來說還是相當具有挑戰性的。畢竟上面這些圖像分辨率不高,臉也不在同一位置,一些圖上還有文字,甚至很多圖都有手對面部進行了遮擋。


          但與此同時,越復雜多樣的圖片訓練出的模型泛化能力就會越好。

          # 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")
          


          數一下每種表情的數量,我們得到:

          4103 fear images
          436 disgust images
          4982 neutral images
          7164 happy images
          3993 angry images
          3205 surprise images
          4938 sad images
          


          不難看出,除了“厭惡”的表情,其他每種表情的數量基本是平衡的。


          設置數據生成器


          Keras的ImageDataGenerator類可以從路徑中提供批量數據:

          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.
          


          訓練集中共有28821張表情圖片;驗證集中共有7066張表情圖片。值得一提的是,此處還可以在獲取圖像時執行數據增強(比如隨機旋轉和尺度縮放等)。上文代碼中函數flow_from_directory()用于指定生成器以何種方式導入圖像(路徑,圖像大小,顏色等)。


          設置卷積神經網絡(CNN)


          先來定義我們的CNN網絡架構:

          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個卷積層和2個全連接層,卷積層負責從圖像中提取相關特征,全連接層用于對圖像進行分類。我們使用ReLU函數在CNN中引入非線性,并使用BN(批量標準化)來提高網絡性能。此外,通過Dropout來減少過擬合。我們選用交叉熵作為損失函數,激活函數選用常用于多分類任務的Softmax函數。

          現在我們已經定義了CNN,讓我們正式開始訓練吧!


          訓練模型

          # 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
          


          從迭代輸出中不難看出,我們的模型能夠達到的最高驗證準確度為65%,這可能并不算高,但對于多分類任務來說,已經相當不錯了。


          我們將CNN的結構保存到文件中:

          # serialize model structure to JSON
          model_json=model.to_json()
          with open("model.json", "w") as json_file:
           json_file.write(model_json)
          


          分析結果


          我們通過訓練過程中保存的數據來繪制訓練集和驗證集的損失和準確度演變曲線:

          # 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()
          


          隨著訓練的迭代次數增加,損失和準確度的演變


          除了損失和準確度演變曲線,我們還可以通過繪制混淆矩陣來幫助我們了解我們的模型是如何對圖像進行分類的:

          # 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()
          



          從混淆矩陣的結果來看,我們的模型在預測“高興”和“驚訝”的表情時表現非常優秀,但是在預測“恐懼”的表情時則比較頭疼,因為容易和“悲傷”的表情相混淆。

          不管怎樣,隨著研究進一步深入以及更廣泛的資源獲取,模型性能肯定能得到優化和改善。下面,是時候在真實場景下檢測我們的模型性能了。我們將使用Flask,以便通過網絡攝像頭的視頻輸入進行表情的實時檢測。


          實時預測


          首先我們先創建一個類,它將為我們提供先前訓練模型的預測:

          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)]
          


          接下來我們將實現一個能夠執行以下操作的類:

          1) 從網絡攝像頭獲取圖像流

          2) 使用OpenCV檢測并框出人臉

          3) 從我們的CNN網絡獲取預測結果并將預測標簽添加到網絡攝像頭的圖像流中

          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()
          


          你以為這就完了?


          還沒,我們將創建一個Flask應用程序,將我們的表情預測結果呈現到網頁中。

          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)
          


          激動人心的時刻到了,下面讓我們一起看看最終的檢測效果吧!

          學會它,你就又習得一項實(shua)用(shuai)新技能。下次群聊發啥表情包,直接甩個表情識別網頁程序過去,分分鐘實力carry秒殺全場。你就是人群中最靚的仔!


          留言 點贊 關注

          我們一起分享AI學習與發展的干貨

          歡迎關注全平臺AI垂類自媒體 “讀芯術”

          年來,圖像識別研究的精確度越來越高,其中“手寫數字識別”作為圖像識別中的一個經典問題,通過“卷積神經網絡(CNN)”的方式,某些解決方案的精確度更是達到了99.1%。大家在網上也能搜索到相應的實現教程,但是大部分教程都比較簡略,缺乏深入淺出的講解,讓初學者們難以上手。

          而且常見的“手寫數字識別”教程往往是僅僅介紹已有的公共數據里的樣本數字的識別方法,這就和實際應用中的“識別自己提供的手寫數字”差距很大。考慮到這些gap,本文就詳細給大家介紹一個更加貼近“實戰”的、更詳細的教程:如何用Keras構建卷積神經網絡識別“自己”的手寫字。

          圖1:手寫字識別示圖

          使用的編程語言:Python。

          使用的依賴包/框架:TensorFlow,Keras。

          使用的模型/方法:卷積神經網絡(Convolutional Neural Network,即CNN)。

          使用的數據集:MNIST數據集--28x28像素的灰度手寫數字圖片--包括60000個訓練樣本和10000個測試樣本(該MNIST數據集為事先處理好的“一個數字一張圖”的標準數據集,背景為純黑色、即byte值為0,數字筆劃為白色,即筆劃的最高值為255)。另有自行上傳的手寫字體圖片約共30個。

          解決的問題/實現的功能:

          1,基于MNIST數據集,訓練一個能識別手寫阿拉伯數字的模型,即能夠將輸入的手寫數字的圖和對應的阿拉伯數字進行匹配(識別)。

          2,用戶將自己創建的手寫數字作為一個圖片、上傳至訓練好的模型中做預測,讓模型識別出對應的數字。

          推薦使用的平臺:達仁云主機【Linux + JupyterLab】公共鏡像。

          圖2:達仁云主機示圖

          可以看到筆者推薦使用“達仁云主機”這個工具(來自于atlas.daren.io)來進行學習和練習,這是因為對于第一次試用CNN、TensorFlow或Keras的同學來說,往往不僅僅缺乏必要的編程和軟件配置知識,也經常缺少合適的硬件主機,例如合適的GPU卡。這樣很多同學一開始上手時需要投入的時間和預算成本就非常高,相當于一個和我們要學習的CNN基本知識和應用并不是密切相關、不必要的“高門檻”。

          使用類似于“達仁云主機”這樣的產品可以大大降低同學們一開始上手的難度。雖然同樣是采用云上租用虛擬機的方式使用,“達仁云主機”的特殊之處在于是“立即可用”的“預設+托管”型云主機(managed cloud PC):“達仁云主機”是預先安裝好基礎軟件(例如這里會用到的JupyterLab)、配置好軟件和網絡設置(例如立即可以在瀏覽器里直接登錄訪問這個云主機上的JupyterLab)、并且“自動化+智能”處理好鏡像存儲和數據持久化等一些云主機的常見問題。

          用“達仁云主機”這種瀏覽器中立即可用的“預設+托管”型云主機來做CNN的學習和練習,就會更加容易上手、直接進入CNN知識和技能學習的“核心區”。

          基于達仁云主機這樣的簡易設定,我們在網頁上僅需不斷點擊“下一步”,就能啟動一臺所需環境和配置的云主機。“達仁云主機”其實就是把平時需要“看懂一整本教程書”以后才能用起來的“云主機”的那些復雜的設置和維護“智能化/傻瓜化”,讓用戶僅需點擊幾個按鈕,就能在瀏覽器里直接啟動一臺“立即能用”的云主機。

          特別方便的是“達仁云主機”通過一個普通瀏覽器即可訪問,不需要安裝任何軟件或購買任何硬件。云主機啟動后是按秒計費,停機就立刻停止計費,沒有“包月”的門檻,“省心省錢”。“達仁云主機”更有百余種云主機配置可選,其中就包括很多款適合做CNN機器學習使用的、帶GPU卡的云主機類型。

          這些特色就讓很多因為沒有預算(適合做AI的GPU卡現在可是幾千元甚至上萬元一張)、或者被各種云計算教科書“望而卻步”過的同學能夠“省心省事”地立即開始用上合適的AI學習環境。

          注意了,這個達仁云主機提供的開發環境和計算資源,是真正可以做開發、做項目的“實戰”級環境,可不是一些常見的“只能做作業”的“假”的模擬開發環境哦~

          好了,我們開始進入正題,筆者將本教程分為三部分

          一、達仁云主機三分鐘開啟環境篇

          1.1、創建虛擬硬盤;

          1.2、選擇公共鏡像;

          1.3、配置JupyterLab云主機;

          1.4、從終端配置環境。

          二、建模型篇:模型訓練與評估

          2.1、導入所需的依賴包與框架

          2.2、如何對數據預處理;

          2.3、如何訓練模型;

          2.4、如何評估模型。

          三、用模型篇:使用模型識別輸入的手寫字體

          3.1、嘗試識別在便箋上寫的數字;

          3.2、嘗試識別白紙作為背景的手寫數字;

          3.3、嘗試識別手寫字體網站截取的手寫數字;

          3.4、嘗試識別在Atlas OS筆記功能里手寫的數字。

          注意:本教程涉及的數據、Python代碼、對應結果,都在本文的圖文教程中全部提供,并可以在https://gitee.com/diagnoa/public/tree/master/tutorial/CNN-general-tutorial-01下載到。

          一、達仁云主機三分鐘開啟環境篇

          1.1、創建虛擬硬盤

          在瀏覽器中登錄Atlas OS(atlas.daren.io),選擇左側導航欄中的達仁云主機,在達仁云主機界面創建虛擬硬盤,使用此硬盤作為主要的數據和運行目錄。

          圖1. 啟動云主機界面

          1.2、選擇公共鏡像

          達仁云主機為用戶“預設配置好”的JupyterLab、RStudio、Eclipse等多種開發環境及Windows、Linux遠程桌面,這里我們選擇Linux + JupyterLab鏡像。

          圖2.選擇主機鏡像界面

          1.3、配置JupyterLab云主機

          點擊啟動云主機后,我們依次選擇GPU類型的云主機g4dn.xlarge,設置虛擬硬盤大小,設置合適的內存,為云主機命名,然后點擊啟動。

          圖3. 選擇配置GPU實例界面

          達仁云主機提供百余種配置可選(CPU : 1~96核、內存:0.5GB~3TB、硬盤:1GB~16TB),費用低至3分錢/小時起,可以隨時開啟和關閉。當云主機狀態由“啟動中”變為“運行中”時,便可在啟動JupyterLab后進行后續操作。此教程提供從IP啟動的例子。

          圖4. 云主機啟動中狀態界面

          圖5. 云主機運行中狀態界面

          圖6. 使用IP啟動云主機界面

          此時瀏覽器會打開Jupyter的操作界面,輸入系統分配的初始密碼即可登陸。

          圖7. 輸入密碼登陸Jupyter

          1.4、打開終端配置環境

          圖8. 使用終端界面

          圖9. 終端界面

          輸入密碼登錄后,在圖9界面中鍵入如下代碼安裝程序運行所需環境

          # 安裝必要的系統環境,即所依賴的系統程序和編譯工具

          # 此鏡像默認安裝了conda環境,所有的操作可以在base這個環境中進行

          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驅動

          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環境

          conda install -c anaconda tensorflow-gpu keras matplotlib pillow -y

          conda install -c conda-forge opencv -y

          至此本次教程所需環境已經配置完畢,我們就可以使用Jupyter Notebook開始執行代碼。

          圖10. 打開Jupyter Notebook界面


          二、建模型篇:模型訓練與評估

          2.1、導入所需的依賴包與框架

          # 在程序的開始,導入待使用的包

          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、如何對數據做預處理

          # 加載數據

          # 注意:一般模型訓練需要區分訓練數據(train)和測試數據(test),測試數據不可以在訓練過程中使用,以便在訓練過程結束以后,能夠用測試數據來評估所訓練的模型的性能。

          (X_train, y_train), (X_test, y_test) = mnist.load_data()

          # 將輸入數據reshape成CNN期望的格式(也就是將圖像數據轉成神經網絡能識別的數組數據)

          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')

          # 將輸入數據歸一化

          # 注意1:一般CNN數據的歸一化(Normalization)是將數據轉化到[0, 1]這個區間里(把數值變小一些)。因為如果輸入數據里的數據值過大(例如幾百或上萬),將會造成模型訓練時的時間過長、輪數過多(造成這個現象的一個原因:一些小的初始化系數項需要經過很多輪的訓練才能“適應”包含“大數值”的變量項),而且很有可能會導致訓練失敗。所以一般所有的機器學習前,都需要對數據進行預處理,例如歸一化或標準化。

          # 注意2:數據的歸一化和標準化(Standardization)和中心化(Centering)是三種不同(但聯系緊密)的操作。此處使用的是歸一化。對于基本符合正態分布的數據,建議使用標準化的預處理。

          X_train /= 255

          X_test /= 255

          # 將輸出數據類別變為one hot編碼 (one hot encoding)

          # 為什么這里要做one hot編碼呢?因為神經網絡無法識別常規的分類變量(categorical data)。感興趣的同學可以在這里看一看做one hot編碼的詳細背景和原因: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、如何訓練模型

          # 創建模型

          # 創建模型有時候可以說一種“藝術”,因為模型的選擇,例如各個層的參數選擇多種多樣,而模型中層與層之間的關系更是可以“千奇百怪”,這里僅僅提供了一種常見的適合于MNIST數據的網絡。感興趣的同學們可以閱讀Keras和PyTorch文檔里關于網絡中不同層的各種類型的作用和其配置參數影響的介紹,創建自己的網絡結構,來試一試:

          # https://keras.io/api/layers/convolution_layers/

          # https://pytorch.org/docs/stable/nn.html#convolution-layers

          # 注:給一個“模型”嘗試不同結構和不同參數(即常常提到的一個模型的“超參數”,hyperparameter)設置,找到最優化的模型超參數,往往需要嘗試成千上萬種潛在的模型結構和配置,這也是為什么在機器學習實戰中,模型的創建和優化是如此的消耗資源(在成千上萬個機器節點上跑不同的模型,或者在一個機器上跑成千上萬個不同的模型)。

          num_classes = 10 # 代表0-9共10個數字,10種類別。

          input_shape = (28, 28, 1) # 輸入數據shape為28x28x1。

          model = Sequential(

          [

          keras.Input(shape=input_shape), # 定義輸入層,設置輸入層為與訓練數據相同的維度。

          Conv2D(32, kernel_size=(3, 3), activation="relu"), # 定義卷積層網絡,本層需要學習32個卷積核,卷積核大小為3x3。激活函數為Relu。

          MaxPooling2D(pool_size=(2, 2)), # 疊加池化層,池化窗口形狀為2×2的最大池化。

          Conv2D(64, kernel_size=(3, 3), activation="relu"), # 疊加卷積層網絡。

          MaxPooling2D(pool_size=(2, 2)), # 疊加池化層。

          Flatten(), # 將輸入“壓平”,即把多維的輸入一維化,常用在從卷積層到全連接層的過渡。

          Dropout(0.5),# Dropout將在訓練過程中每次更新參數時按一定概率(0.5)隨機斷開輸入神經元,可防止過擬合。

          Dense(num_classes, activation="softmax"),# 全連接層,輸出層,激活函數為softmax。

          ]

          )

          # 打印模型信息

          model.summary()

          運行上述代碼,輸出結果為:

          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

          ___________________________________________________________

          上述結果打印了模型的相關信息:從左至右依次為網絡每一層的信息、每一層的輸出結果的樣式、每一層的參數個數。打印這些信息可以幫助我們更直觀地了解所構建模型的結構。

          # 訓練模型

          # 注:一般訓練模型是最消耗時間的步驟,這里可能會需要等一段時間

          batch_size = 128 # 設置batch size

          epochs = 15 # 設置epoch。

          model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

          # 模型的loss選擇categorical_crossentropy, 優化器選擇adam,metrics選擇accuracy。

          model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1) # 用訓練數據訓練模型,并按照0.1的比例抽取數據進行validation。

          運行上述代碼,輸出結果省略中間部分,展示如下:

          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

          上述結果打印了模型訓練過程中loss的變化。在模型訓練時,選擇了categorical cross entropy作為loss,來衡量原始數字類別和由模型預測的數字類別的差異。loss值越小,說明預測結果與原始結果越相似。打印結果中loss是訓練過程產生的,val_loss是驗證過程產生的,val_accuracy是指validation過程中的準確性。計算的準確性越高效果越好。

          2.4、如何評估模型

          # 用測試數據評估模型

          score = model.evaluate(X_test, y_test, verbose=0) # 用測試數據評估模型,不輸出中間過程

          print("Test loss:", score[0]) # 打印loss值

          print("Test accuracy:", score[1]) # 打印accuracy

          # 運行上述代碼,輸出結果為:

          Test loss: 0.027751104906201363 # 測試數據的loss

          Test accuracy: 0.991100013256073# 測試數據類別的準確性達到99.1%

          所以如果僅僅拿MNIST數據集里數據做評估的話,那么這個模型的準確性相當的高,達到了99.1%。但是如果拿來“實用”一下呢?我們來看看這個模型能不能識別我們自己手寫的數字。


          三、用模型篇:使用模型識別輸入的手寫字體

          生活中的事一般都是“理想很豐滿,現實很骨感”,真的要讓一個模型把一個手寫的數字給識別出來,其實還真不是那么容易的。我們一起來看一下吧:

          3.1、嘗試識別在便箋上寫的數字

          我們先試一試“隨便”地在便簽紙上寫一個簡單的數字,讓這個模型來試一下吧。在一張最普通最常見的(就是淺黃色的那種)便箋上寫一個數字(如我們圖中的這個“扭曲的0”),然后拍照后存到電腦(或云主機)里,先試一下吧。

          注:讓模型識別一個普通圖像里的數字可不是那么“簡單/直接”的,需要很多個“把一般的彩色照片圖像轉換成模型可以讀取的數組”的操作步驟。例如下面這整整15行的代碼就是做這個的:

          pic = '/home/diagnoa/DataDrive/WechatIMG1.jpeg' # 手寫字原始圖片

          img = Image.open(pic) # 讀取圖片文件

          ax = plt.subplot(1, 2, 1) # 選擇畫布1行2列區域的左邊繪圖

          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列區域的右邊繪圖

          target_shape = (28,28) # 設置數據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() # 畫圖

          因為MNIST訓練的模型要求的輸入圖片是(28x28x1)的灰度圖,且數值是在0-1之間并且背景反轉的(即背景為黑色,byte值為0,筆劃信號為正值,這樣在轉化出的數組中方便直觀觀察)。此處我們使用的手寫數字的照片在經過了上述的預處理之后,我們并不確定還有多少有效信息得到了保留。因此為了能夠盡可能地對比原始圖片和輸入模型的圖片,上述代碼對預處理之后的圖片做了可視化,即上面的這一部分代碼中的使用到plt函數的這些行。

          注:此處做預處理的代碼參考的網絡資料來源:

          1. https://blog.tanka.la/2018/10/28/build-the-mnist-model-with-your-own-handwritten-digits-using-tensorflow-keras-and-python/
          2. https://www.tutorialkart.com/opencv/python/opencv-python-resize-image/

          主站蜘蛛池模板: 日本一道一区二区免费看| 一区二区三区免费电影| 亚洲国产美女福利直播秀一区二区| 亚洲色无码专区一区| 中文无码精品一区二区三区| 国产精品盗摄一区二区在线| 国产精品视频一区二区三区经| 亚洲线精品一区二区三区 | 中文字幕在线观看一区 | 少妇精品无码一区二区三区| 精品国产一区二区三区2021| 婷婷亚洲综合一区二区| 亚洲精品伦理熟女国产一区二区| 国产精品熟女一区二区| 久久国产香蕉一区精品| 成人国产精品一区二区网站| 国产成人无码aa精品一区 | 无码人妻精品一区二区三18禁| 久久亚洲色一区二区三区| 一区二区三区在线播放视频| 精品在线一区二区三区| 日韩AV在线不卡一区二区三区 | 亚洲国产激情一区二区三区 | 久久无码一区二区三区少妇| 一区二区三区电影在线观看| 中文字幕国产一区| 亚洲AV日韩AV天堂一区二区三区 | 精品一区二区ww| 无码人妻一区二区三区av| 国模精品视频一区二区三区| 国产成人AV区一区二区三| 精品一区二区三区在线播放| 国产精品99无码一区二区| 国产一区二区三区精品视频| 国产一区二区三区在线看| 97精品一区二区视频在线观看| 亚洲一区二区三区高清不卡| 国产人妖视频一区二区破除| 亚洲一区日韩高清中文字幕亚洲| 国产一区二区三区在线观看精品| 无码人妻精品一区二区|