一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

搭建和部署手語AI識別系統

 天承辦公室 2022-12-29 發(fā)布于江蘇

據北京聽力協會預估數據,我國聽障人群數量已過千萬。而在全球范圍內有4.66億人患有殘疾性聽力損失,約占全世界人口的5%。聾啞人士很特殊,他們需要使用手語進行交流,其他與常人無異,我國存在特殊教育水平在各城市中發(fā)展力度具有較大差異,國家通用手語推廣程度淺,但不懂手語,與聽力障礙者交流會非常困難。

在本篇內容中,ShowMeAI 借助深度學習與神經網絡技術,針對這個問題從 0 構建 1 個應用程序,檢測手語并將其翻譯給其他人進而打破手語隔閡。

文章圖片1

搭建和部署完成后,你可以通過攝像頭,輕松測試模型,如下圖所示,快來一起試試吧。這個動圖中的手勢代表的單詞,見文末哦!

手語介紹

我們先來簡單了解一下手語,它由 3 個主要部分組成:

  • 手指拼寫:這是一種手動的交流方式,用雙手和手指拼寫單詞。每個字母都用指定的手位置表示。
  • 單詞級符號詞匯:這是一個大型視頻數據集,用于識別單詞或字母的整個手勢。
  • 非手部特征:包括任何面部表情、嘴巴、舌頭或身體姿勢。
文章圖片2

在本文中,我們先解決第①個部分的問題。我們準備使用的解決方案是基于視覺數據的神經網絡

深度學習與計算機視覺

人工智能和計算機視覺的最典型的模型是卷積神經網絡(CNN),它在典型的計算機視覺應用中(如圖像識別、目標檢測等)應用廣泛。我們在本次應用的核心技術也將采用 CNN。

文章圖片3

CNN 網絡有著如上圖所示的網絡結構,典型的結構包括卷積層、池化層、激活層、全連接層等,對于輸入圖像,可以有效抽取圖像內容表征,并進行分類或其他處理。卷積層等特殊結構,可以在控制參數量的前提下,保證良好的圖像特征提取能力。

小試牛刀,打通流程

我們來構建一個 CNN 識別的流程,會分成以下基礎步驟:

  • 數據讀取與切分
  • 數據可視化及預處理
  • CNN網絡構建與訓練

① 導入相關庫

我們在這里主要使用 TensorFlow 構建網絡與訓練,會使用 Numpy 做數據計算與處理,以及使用 Matplotlib 進行簡單可視化。

我們先把這些工具庫導入。

# 導入工具庫import stringimport pandas as pdimport numpy as npimport tensorflow as tfimport matplotlib.pyplot as pltfrom tensorflow import kerasfrom functools import partialfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, array_to_img

② 讀取數據集

本數據集為手語字母對應的數據集,圖片 size 不大,所以也叫做 sign_mnist 數據集(類比手寫數字數據集 mnist),部分示例圖片如下

文章圖片4

下面我們加載訓練集與測試集并切分特征與標簽:

# 讀取數據test = pd.read_csv('sign_mnist_test.csv')train = pd.read_csv('sign_mnist_train.csv') # 輸出基本信息print('訓練集維度', train.shape)print('測試集維度', train.shape)
# 輸出標簽信息labels = train['label'].value_counts().sort_index(ascending=True)labels
# 切分特征與標簽train_x = train.drop(labels = 'label', axis = 1)train_y = train['label']test_x = test.drop(labels = 'label', axis = 1)test_y = test['label']train_x.head()
# 數據預處理與可視化# 存儲標簽數據test_classes= test_ytrain_clasees = train_y # 特征轉為numpy格式train_x = train_x.to_numpy()test_x = test_x.to_numpy() # 把數據轉為3維圖像數據(圖片數量*寬*高,這里如果是灰度圖,顏色通道為1,省略)train_x = train_x.reshape(-1,28,28)test_x = test_x.reshape(-1,28,28)
# 在訓練集中取樣30張圖片,做可視化查看def plot_categories(training_images, training_labels): fig, axes = plt.subplots(3, 10, figsize=(16, 15))    axes = axes.flatten()    letters = list(string.ascii_lowercase)     for k in range(30):        img = training_images[k]        img = np.expand_dims(img, axis=-1)        img = array_to_img(img)       ax = axes[k]        ax.imshow(img, cmap='Greys_r')        ax.set_title(f'{letters[int(training_labels[k])]}')        ax.set_axis_off()     plt.tight_layout()    plt.show() plot_categories(train_x, train_y)
文章圖片5

③ 卷積神經網絡CNN搭建

我們使用 TensorFlow 的 high level API(即keras)搭建一個簡易CNN神經網絡,并擬合一下數據

def create_model(): model = tf.keras.models.Sequential([ # 卷積層 tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)), # 池化層 tf.keras.layers.MaxPooling2D(2,2), # 卷積層 tf.keras.layers.Conv2D(32, (3,3), activation='relu'), # 池化層 tf.keras.layers.MaxPooling2D(2,2), # 展平 tf.keras.layers.Flatten(), # 全連接層 tf.keras.layers.Dense(512, activation='relu'), # softmax分類 tf.keras.layers.Dense(26, activation='softmax')]) model.compile( optimizer='adam', #優(yōu)化器 loss='sparse_categorical_crossentropy', #損失函數 metrics=['accuracy']) #評估準則 return model
# 初始化模型model = create_model()# 擬合數據history = model.fit(train_x, train_y, epochs=20, validation_data=(test_x, test_y))

我們這里在全量數據集上迭代20個輪次,結果如下:

文章圖片6

我們可以看到,這里的數據并不特別復雜,在自己從頭搭建的 CNN 模型上,經過訓練可以達到訓練集 100% 驗證集 92% 的準確率。

我們再對訓練過程中的「準確率」及「損失函數」變化值進行繪制,以了解模型狀態(tài)。

# 獲取準確率與損失函數情況acc = history.history['accuracy']val_acc = history.history['val_accuracy']loss = history.history['loss']val_loss = history.history['val_loss'] # matplotlib繪制訓練過程中指標的變化狀況epochs = range(len(acc)) plt.plot(epochs, acc, 'r', label='Training accuracy')plt.plot(epochs, val_acc, 'b', label='Validation accuracy')plt.title('Training and validation accuracy')plt.legend()plt.figure()plt.plot(epochs, loss, 'r', label='Training Loss')plt.plot(epochs, val_loss, 'b', label='Validation Loss')plt.title('Training and validation loss')plt.legend() plt.show()
文章圖片7

問題與優(yōu)化

① 深度網絡與梯度消失

一般來說,隨著 CNN 網絡層數變深,模型的學習能力會變強,也能學到更多的信息。但訓練深度CNN存在梯度消失的問題。

文章圖片8

非常深的神經網絡的梯度會很快變?yōu)榱悖ǚ聪騻鞑サ奶荻冗B乘帶來的問題),這最終會使整個梯度下降變慢。有一些特殊結構的神經網絡,可以大程度緩解這個問題,比如最著名的 ResNet,當然,大家可以借助 ResNet 預訓練模型快速遷移學習應用在我們當前的手語識別問題上,為了讓大家對ResNet 細節(jié)更清晰,我們在這里手動搭建 ResNet-50(即50層的ResNet網絡)來訓練和做效果對比。

② ResNet 模型簡介

ResNet 是 Residual Networks 的簡稱,是迄今為止我們看到的最流行和最成功的深度學習模型之一。ResNets 由殘差塊組成,殘差塊的核心組件是『跳躍連接/skip-connection』。跳躍連接,也稱為快捷連接,讓神經網絡跳過某些層并將一層的輸出饋送到神經網絡中另一層的輸入。它能幫助模型避免乘以中間跳過的那些層的權重,從而有助于解決梯度消失的問題。

然而,使用 ResNet 和跳躍連接,由于中間有卷積層和池化層,一層輸出的維度可能與另一層的輸出維度不同。為了解決這個問題,可以使用兩種方法:

  • 快捷連接填充多個零實體以增加其維度
  • 添加 1X1 卷積層來匹配維度。

但是,對于第二種方法,我們需要在輸出中添加一個額外的參數,而第一種方法不需要。

③ ResNet為何有效

ResNet的效果核心有2點:

  • ① 它使用我們上面提到的跳躍連接,它跳過層來解決梯度消失的問題。
  • ② 它通過讓模型學習恒等函數來確保最高層的性能至少與最低層一樣好。

④ 構建ResNet-50

下面我們參考 keras 官方 ResNet 構建方式,構建一個 ResNet-50,如下所示,我們先構建基本模塊,再組裝成最終的網絡。

# Defining the identity block of the Resnet-50 Model. def identity_block(X, f, filters, training=True):    # filter of the three convs     f1,f2,f3 = filters    X_shortcut = X         # First Component     X = tf.keras.layers.Conv2D(filters = f1, kernel_size = 1, strides = (1,1), padding = 'valid')(X)    X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axis    X = tf.keras.layers.Activation('relu')(X)       # Second Component    X = tf.keras.layers.Conv2D(filters = f2, kernel_size = f, strides = (1,1), padding = 'same')(X)X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training)# Default axis    X = tf.keras.layers.Activation('relu')(X)# Third Component    X = tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (1,1), padding = 'valid')(X)    X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axis        # Adding the two tensors     X = tf.keras.layers.Add()([X_shortcut,X])    X = tf.keras.layers.Activation('relu')(X)# Returning the last output    return X
# Defining the Convolution Block of the Resnet-50 Model. def convolutional_block(X, f, filters, s=2,training=True): # filter of the three convs f1,f2,f3 = filters X_shortcut = X # First Component X = tf.keras.layers.Conv2D(filters = f1, kernel_size = 1, strides = (1,1), padding = 'valid')(X) X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axis X = tf.keras.layers.Activation('relu')(X) # Second Component X = tf.keras.layers.Conv2D(filters = f2, kernel_size = f, strides = (s,s), padding = 'same')(X) X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axis X = tf.keras.layers.Activation('relu')(X) # Third Component X = tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (1,1), padding = 'valid')(X) X = tf.keras.layers.BatchNormalization(axis = 3)(X, training = training) # Default axis # Converting the Input Volume to the match the last output for addition. X_shortcut =tf.keras.layers.Conv2D(filters = f3, kernel_size = 1, strides = (s,s), padding = 'valid')(X_shortcut) X_shortcut = tf.keras.layers.BatchNormalization(axis = 3)(X_shortcut, training = training) X = tf.keras.layers.Add()([X_shortcut,X]) X = tf.keras.layers.Activation('relu')(X) # Adding the last two tensors X = tf.keras.layers.Add()([X, X_shortcut]) X = tf.keras.layers.Activation('relu')(X) # Returning the output tensor return X
# Defining a modified Resnet-50 Model using the Identity and Convolution Blocks. def ResNet50(input_shape = (28, 28, 1), classes = 26):        # Defining the input as a tensor with shape input_shape    X_input = tf.keras.Input(input_shape)        # Zero-Padding    X = tf.keras.layers.ZeroPadding2D((3, 3))(X_input)        # Stage 1   X = tf.keras.layers.Conv2D(64, (5, 5), strides = (1, 1))(X)    X = tf.keras.layers.BatchNormalization(axis = 3)(X)    X = tf.keras.layers.Activation('relu')(X)    X = tf.keras.layers.MaxPooling2D((3, 3), strides=(2, 2))(X)     # Stage 2    X = convolutional_block(X, f = 3, filters = [64, 64, 256], s = 1)    X = identity_block(X, 3, [64, 64, 256])    X = identity_block(X, 3, [64, 64, 256])        # Add an Average Pool Layer    X = tf.keras.layers.AveragePooling2D((2,2))(X)    # Output Layer    X = tf.keras.layers.Flatten()(X)    X = tf.keras.layers.Dense(classes, activation='softmax')(X)        # Create Model    model = tf.keras.Model(inputs = X_input, outputs = X)     return model

⑤ 訓練ResNet-50

下面我們在數據集上,使用 ResNet-50 網絡進行訓練

# 初始化模型model = ResNet50() # 編譯model.compile(optimizer='adam',metrics=['accuracy'],loss = 'sparse_categorical_crossentropy') # 訓練history = model.fit(train_x, train_y, validation_data = (test_x, test_y), epochs =10)

得到如下結果

文章圖片9

優(yōu)化效果對比

我們對ResNet-50也繪制訓練過程中準確率和損失函數的變化,如下

# 獲取準確率與損失函數情況acc = history.history['accuracy']val_acc = history.history['val_accuracy']loss = history.history['loss']val_loss = history.history['val_loss'] # matplotlib繪制訓練過程中指標的變化狀況epochs = range(len(acc)) plt.plot(epochs, acc, 'r', label='Training accuracy')plt.plot(epochs, val_acc, 'b', label='Validation accuracy')plt.title('Training and validation accuracy')plt.legend()plt.figure() plt.plot(epochs, loss, 'r', label='Training Loss')plt.plot(epochs, val_loss, 'b', label='Validation Loss')plt.title('Training and validation loss')plt.legend()plt.show()

對比圖如下:

文章圖片10

我們觀察到,從簡單的 CNN 模型換到 ResNet 模型時,測試集的準確率從92% 到 97% 。也說明了,ResNet 的結構確實能夠帶來效果上的提升。

部署與實時測試

在這里我們做一個簡單的測試,使用 OpenCV 的視頻錄制功能,通過 python 收集我們的攝像頭的鏡頭采集的圖像并進行實時預測。

ShowMeAI給OpenCV工具庫制作了快捷即查即用的 OpenCV 速查表手冊,大家可以點擊查看和下載。

具體的過程是,我們解析捕獲的每一幀圖像,將其處理為灰度圖(類似于我們模型的訓練集),在圖像中心抓取一個 400*400 像素的正方形區(qū)域(參見 x0,x1,y0,y1),將正方形調整為我們最初的 28x28 大小并使用我們的模型進行測試(之前保存到 .h5 文件)。

# 導入工具庫import kerasimport numpy as npfrom PIL import Imageimport stringimport pandas as pdimport tensorflow as tf
# 導入OpenCVimport cv2from matplotlib import pyplot # 設定維度dim = (28, 28) # 圖像維度letters = list(string.ascii_lowercase) # 識別的字母 x0 = 1920 // 2 - 400 # 400px left of centerx1 = 1920// 2 + 400 # 400px right of centery0 = 1080// 2 - 400 # 400px right of centery1 = 1080// 2 + 400 # 400px right of center # 初始化視頻捕獲video=cv2.VideoCapture(0)cv2.namedWindow('Webcam') # 構建1個窗口cv2.moveWindow('Webcam',40,30) # 放置窗口 while video.isOpened(): # 只要沒有關掉實時攝像頭   ret,capture = video.read() # 抓取每個視頻幀    cropped = capture[y0:y1, x0:x1] # 截取    img = cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY) # 轉成灰度圖   img = cv2.GaussianBlur(img, (5, 5), 0) # 圖像平滑    img = cv2.resize(img, dim) # 圖像大小縮放    pyplot.imshow(img, cmap='gray')# 可視化展示圖片    pyplot.show() # 展示    img = np.reshape(img, (1,img.shape[0],img.shape[1],1))   img = tf.cast(img, tf.float32)    pred=model.predict(img)     # 可視化實時效果    cv2.rectangle(capture, (x0,y0),(x1,y1),(255,0,0),2) # 為圖片添加矩形框    cv2.putText(capture,'{} res50'.format(letters[np.argmax(pred[0])]),(x0+25,y0+50),cv2.FONT_HERSHEY_SIMPLEX,0.9,(0,255,0),1) # 預測字母   cv2.imshow('Webcam', capture) # 展示視頻       # 結果輸出    print(pred)    print(letters[np.argmax(pred[0])])# 退出視頻輸入   key = cv2.waitKey(1)   if key == ord('q'):       breakvideo.release()cv2.destroyAllWindows()

為了更輕松地對預估結果查看,我們把將預測的字母顯示在實時畫面上(請參閱下面的 gif 以測試單詞 hello)。

文章圖片11

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日韩国产传媒在线精品| 亚洲中文字幕熟女丝袜久久| 日韩国产亚洲欧美另类| 久久大香蕉一区二区三区| 国产欧洲亚洲日产一区二区| 亚洲国产精品国自产拍社区| 免费特黄欧美亚洲黄片| 大屁股肥臀熟女一区二区视频| 国产美女精品人人做人人爽| 亚洲av一区二区三区精品| 99在线视频精品免费播放| 高潮少妇高潮久久精品99| 中文字幕av诱惑一区二区| 国产精品亚洲欧美一区麻豆| 成年人黄片大全在线观看| 香蕉网尹人综合在线观看| 深夜福利亚洲高清性感| 欧美日韩免费观看视频| 久久精品久久精品中文字幕| 日韩黄片大全免费在线看| 国产午夜福利在线免费观看| 国产麻豆一线二线三线| 俄罗斯胖女人性生活视频| 亚洲国产av在线视频| 麻豆剧果冻传媒一二三区| 欧美日韩三区在线观看| 欧美久久一区二区精品| 欧美日韩精品视频在线| 老司机精品一区二区三区| 五月激情婷婷丁香六月网| 91欧美亚洲精品在线观看| 日韩在线中文字幕不卡| 欧美亚洲三级视频在线观看| 国产又粗又猛又大爽又黄同志| 亚洲午夜精品视频观看| 国产麻豆一线二线三线| 日本午夜福利视频免费观看| 青青草草免费在线视频| 九九热这里只有精品视频| 亚洲最新的黄色录像在线| 欧洲偷拍视频中文字幕|