【TensorFlow2&Keras】訓練手語圖像數據集--基於卷積神經網絡CNN

一、前言

在手語視頻識別中,視頻序列大約有幾十甚至上百張圖片,因此手語識別數據集由萬張以上圖片組成,需要檢測大量的數據樣本。

對手語中的手勢檢測任務,可將它作爲目標檢測的一個分支,視爲分類迴歸任務。從中國手語的圖例來看,可以得到以下幾個特性:

  1. 手語圖像序列中,左右手有着不同的形狀軌跡信息,人手因運動而產生模糊的情況經常出現。運動中存在大量的雙手相交或接觸的情況,人手不斷進行着單手向雙手,雙手向單手之間的過渡轉換,而且具有單雙手難以區分的特點;
    在這裏插入圖片描述 在這裏插入圖片描述在這裏插入圖片描述
  2. 手語中的手勢伴隨着人臉,手臂等大量類膚色區域的干擾,並且經常出現手與臉之間,手與手臂之間的遮擋
    在這裏插入圖片描述
  3. 手勢區域小卻包含豐富的信息,由於手語中手形複雜多變而且特殊手形多,但是手勢在圖片中卻總是隻有很少的像素區域,而且往往分辨率低;
    在這裏插入圖片描述
  4. 中小詞彙量手語識別中需要用到大量(幾千個)的手語視頻序列,每21個視頻序列大約有百張圖片,因此手語識別數據集由萬張以上圖片組成,需要檢測大量的數據樣本。

二、入門參考–mnist數據集

環境:win10 + anaconda3 + TensorFlow 2 + keras

第一步:安裝包

  • 精確除法
  • tf 深度學習模型
  • keras是tf2最經典的數據集處理工具,深度學習模型的設計、調試、評估、應用和可視化
  • plt 繪圖
from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt

第二步:下載數據集(可以在線下載)

注意:
在這裏插入圖片描述

官網示例——CIFAR10數據集
該數據集共有60000張彩色圖像,這些圖像是32*32,分爲10個類,每類6000張圖。
在這裏插入圖片描述

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0

或者:(後面我用的這一個演示)

經典示例——mnist數據集
這是手寫數字的數據集,來自美國國家標準與技術研究所, National Institute of Standards and Technology (NIST). 訓練集 (training set) 由來自 250 個不同人手寫的數字構成, 其中 50% 是高中學生, 50% 來自人口普查局 (the Census Bureau) 的工作人員. 測試集(test set) 也是同樣比例的手寫數字數據.
在這裏插入圖片描述

from __future__ import absolute_import, division, print_function, unicode_literals
import matplotlib.pyplot as plt

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()

在這裏插入圖片描述

print(x_train.shape, ' ', y_train.shape)
print(x_test.shape, ' ', y_test.shape)
import matplotlib.pyplot as plt
plt.imshow(x_train[0])
plt.show()

在這裏插入圖片描述在這裏插入圖片描述
統一數據集大小


x_train = x_train.reshape((-1,28,28,1))
x_test = x_test.reshape((-1,28,28,1))

第三步:構建模型
通過堆疊圖層構建tf.keras.Sequential模型。選擇用於訓練的優化器和損失函數:

#構造網絡
model = models.Sequential()
#卷積層
model.add(layers.Conv2D(input_shape=(x_train.shape[1], x_train.shape[2], x_train.shape[3]),
                        filters=32, kernel_size=(3,3), strides=(1,1), padding='valid',
                       activation='relu'))
#池化層
model.add(layers.MaxPool2D(pool_size=(2,2)))
#全連接層
model.add(layers.Flatten())
model.add(layers.Dense(32, activation='relu'))
# 分類層
model.add(layers.Dense(10, activation='softmax'))
#模型配置
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.summary() # 顯示模型的架構

模型這裏很重要,選取網絡模型有卷積神經網絡CNN之經典LeNet-5層模型,進化到AlexNet模型,大家可以到網上搜索。這裏是重難點!!!
本次參考的模型源於:tf2實現cnn對mnist分類
在這裏插入圖片描述
第四步:編譯和訓練模型
epochs的次數就是你即將訓練的次數,訓練次數越多越精確,也越耗時。

#模型訓練
history = model.fit(x_train, y_train, batch_size=64, epochs=5, validation_split=0.1)

5次迭代效果:
在這裏插入圖片描述
第五步:評估模型

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.legend(['training', 'valivation'], loc='upper left')
plt.show()

在這裏插入圖片描述

test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_loss, test_acc)

在這裏插入圖片描述
簡單的CNN網絡模型識別率98%😅牛,如果再調調參豈不是…

總結: CNN的過程

Mon 06Mon 13Mon 20導入tf模型 加載數據集 數據集預處理 創建卷積模型 訓練模型 模型評估 CNN卷積神經網絡構建過程

這裏放一個完整的片段:

from __future__ import absolute_import, division, print_function, unicode_literals
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
#加載模型
(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()

#查看數據集的容量
print(x_train.shape, ' ', y_train.shape)
print(x_test.shape, ' ', y_test.shape)
#查看一張圖片
import matplotlib.pyplot as plt
plt.imshow(x_train[0])
plt.show()

#調整圖片的比例大小
x_train = x_train.reshape((-1,28,28,1))
x_test = x_test.reshape((-1,28,28,1))

#構造網絡
model = models.Sequential()
#卷積層
model.add(layers.Conv2D(input_shape=(x_train.shape[1], x_train.shape[2], x_train.shape[3]),
                        filters=32, kernel_size=(3,3), strides=(1,1), padding='valid',
                       activation='relu'))
#池化層
model.add(layers.MaxPool2D(pool_size=(2,2)))
#全連接層
model.add(layers.Flatten())
model.add(layers.Dense(32, activation='relu'))
# 分類層
model.add(layers.Dense(10, activation='softmax'))
#模型配置
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.summary()#顯示模型

#模型訓練
history = model.fit(x_train, y_train, batch_size=64, epochs=5, validation_split=0.1)
#模型評估
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.legend(['training', 'valivation'], loc='upper left')
plt.show()
#識別正確率
test_loss, test_acc = model.evaluate(x_train, y_train)
print(test_acc)

三、訓練自己的圖像數據集

貼一個前人的演示視頻:(侵刪!)

【手勢識別】基於CNN的手勢識別

1. 數據集

我們的手語訓練集在畢業答辯後開源,先用kaggle上的一部分手勢數據集作爲測試樣本:

下載鏈接:https://www.kaggle.com/gti-upm/leapgestrecog
(補充說明:下載需要註冊,科學上網才能驗證。)

參考數據集有10個手勢(1.9G左右):
在這裏插入圖片描述
10個手勢動作:
在這裏插入圖片描述

2.數據集預處理

(1)圖片按0~10類別存放

將分別提取10個人文件夾,每個文件夾有10個手勢,每個手勢有200張圖片;按手勢類型彙總(2000張圖片):
目錄整理(將00-09文件夾的圖片彙總)
在這裏插入圖片描述
主要是:shutil.move()

import os
import shutil
path = 'D:/myworkspace/dataset/leapGestRecog/leapGestRecog/'
n=0
def modlist(path):
    label = 0 #標籤
    #遍歷根目錄
    for i in os.listdir(path):#00~09個人
        file1 = os.path.join(path,i)
        for j in os.listdir(file1):##01-10個手勢
            label=label+1
            file2 = os.path.join(file1,j)
            print("[INFO]file:%s %s"% (file2,j))
            for k in os.listdir(file2):
                img_name = os.path.join(file2,k)
                path2 ='D:/myworkspace/dataset/leapGestRecog/train/'+str(label)+'/'
                if not os.path.exists(path2):
                    os.makedirs(path2)
                shutil.move( img_name , path2+str(k))
        print("[INFO]One Person Finished:",file2)
        label = 0
    print("[INFO]All Finished!")


modlist(path)

移動前後:
在這裏插入圖片描述

3.基於tf2+CNN手勢識別

參考:經典貓狗識別案例,識別10種手勢。

(1)圖像分類

讀取全部彙總的圖像20000張,將圖片按10000:5000:5000比例——分爲訓練集、驗證集和測試集,
目錄結構:

20000
5000
10000
5000
500
500
500
1000
1000
1000
500
500
500
dataset
CNN
test
train
valition
1
...
10
1
...
10
1
...
10

10種手勢訓練圖片各1000張,驗證圖片各500張,測試圖片各500張。

分類代碼:

import os, shutil
# The path to the directory where the original
# dataset was uncompressed
original_dataset_dir = 'D:/myworkspace/dataset/leapGestRecog/orig_data/'

# The directory where we will
# store our smaller dataset
base_dir = 'D:/myworkspace/dataset/CNN/train_data/'

if not os.path.exists(base_dir):
    os.makedirs(base_dir)

# Directories for our training,
# validation and test splits
train_dir = os.path.join(base_dir, 'train')
if not os.path.exists(train_dir):
    os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
if not os.path.exists(validation_dir):
    os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
if not os.path.exists(test_dir):
    os.mkdir(test_dir)

for num in os.listdir(original_dataset_dir):#1~10
    #文件夾1~10
    train_idx_dir = os.path.join(train_dir,num)
    if not os.path.exists(train_idx_dir):
        os.mkdir(train_idx_dir)
    validation_idx_dir = os.path.join(validation_dir, num)
    if not os.path.exists(validation_idx_dir):
        os.mkdir(validation_idx_dir)
    test_idx_dir = os.path.join(test_dir, num)
    if not os.path.exists(test_idx_dir):
        os.mkdir(test_idx_dir)
    #
    original_idx_dir = original_dataset_dir+'/'+num
    #print(original_idx_dir)
    j =0
    for fname in os.listdir(original_idx_dir):#1有2000張
        if j<1000:# Copy next 1000 images to train_idx_dir
            src = os.path.join(original_idx_dir, fname)
            dst = os.path.join(train_idx_dir, fname)
            shutil.copyfile(src, dst)
        elif (j>=1000 and j<1500):# Copy next 500 images to validation_idx_dir
            src = os.path.join(original_idx_dir, fname)
            dst = os.path.join(validation_idx_dir, fname)
            shutil.copyfile(src, dst)
        elif (j>=1500):# Copy next 500 images to test_idx_dir
            src = os.path.join(original_idx_dir, fname)
            dst = os.path.join(test_idx_dir, fname)
            shutil.copyfile(src, dst)
        j=j+1
    print("[INFO]Copy finished! :",train_idx_dir)

print('[INFO]training files:', len(os.listdir(train_dir)))
print('[INFO]validation files:', len(os.listdir(validation_dir)))
print('[INFO]test files:', len(os.listdir(test_dir)))

print('[INFO]1 training images:', len(os.listdir(train_dir+"/1/")))
print('[INFO]1 validation images:', len(os.listdir(validation_dir+"/1/")))
print('[INFO]1 test images:', len(os.listdir(test_dir+"/1/")))

在這裏插入圖片描述

(2)預處理

  • 所有圖片(20000張)重設尺寸大小爲150x150大小
  • ImageDataGenerator就像一個把文件中圖像轉換成所需格式的轉接頭
from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen=ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(train_dir,
                                                    target_size=(150, 150),
                                                    batch_size=20,
                                                    class_mode='binary')
validation_generator = validation_datagen.flow_from_directory(validation_dir,
                                                         target_size=(
                                                             150, 150),
                                                         batch_size=20,
                                                         class_mode='binary')
test_generator = test_datagen.flow_from_directory(test_dir,
                                                   target_size=(150, 150),
                                                   batch_size=20,
                                                   class_mode='binary')

在這裏插入圖片描述

要把圖像讀取格式改爲TensorFlow讀取的格式;這一步卡了我很多天,因爲TensorFlow2用的圖像讀取方式和TensorFlow1的方式大有修改,難受!這裏注意

(3)構建卷積神經網絡

  1. 搭建模型
    model.summary()輸出模型各層的參數狀況
    模型參考的貓狗訓練集採用的模型,至於正則化、圖像增強、參數選取等操作,後續會根據需要來進行。

    from keras import layers
    from keras import models
    
    model = models.Sequential()
    model.add(layers.Conv2D(32, (3, 3), activation='relu',
                            input_shape=(150, 150, 3)))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Flatten())
    model.add(layers.Dense(512, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    model.summary()
    
    

    在這裏插入圖片描述

  2. 模型配置
    model.compile()優化器(loss:計算損失,這裏用的是交叉熵損失,metrics: 列表,包含評估模型在訓練和測試時的性能的指標)

    #模型配置
    from keras import optimizers
    model.compile(optimizer=optimizers.RMSprop(lr=1e-4),
                  loss='binary_crossentropy',
                  metrics=['acc'])
    
  3. 模型大小

    for data_batch,label_batch in train_generator:
        print("data batch shape:",data_batch.shape)
        print("labels batch shape:",label_batch)
        break
    

    在這裏插入圖片描述

(4)訓練模型

這裏epochs=10只訓練了10次

#模型訓練
history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=10, 
    validation_data=validation_generator,
    validation_steps=50)
#保存模型
model.save('D:/myworkspace/dataset/CNN/leapGestRecog_small_1.h5')

(基本上CPU1分鐘跑一次epochs,這裏有條件的話還是上GPU)
在這裏插入圖片描述
在這裏插入圖片描述

loss 損失函數值,與你定義的損失函數值相關
acc 準確率
mean_absolute_error 平均絕對誤差
前面帶val_表示你的模型在驗證集上進行驗證時輸出的這三個值,驗證在每個epoch後進行
一個選拔的故事(acc,loss,val_acc,val_loss的區別):
http://www.pianshen.com/article/5415291383/

(5)模型評估

  1. 結果可視化
#結果可視化
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))
plt.figure(figsize=(15,4))
plt.subplot(1,2,1)
plt.plot(epochs, acc, 'b', label='Training acc',color='green')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.subplot(1,2,2)
plt.plot(epochs, loss, 'bo', label='Training loss',color='green')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()


在這裏插入圖片描述
由結果來看,擬合效果也是比較好的。目前只迭代了10次,如果加強到30,100次,效果會更好。

除此之外,還可以運用 圖片增強的方法、增加模型結構 進行調整模型,能夠大幅度提升準確率。

30次效果:

在這裏插入圖片描述

補充學習:模型評估的方法

模型運用:

from keras.models import load_model

model = load_model('D:/myworkspace/dataset/CNN/leapGestRecog_small_1.h5')
#查看模型結構
model.summary()

#一張測試圖(不在訓練圖集)
img_path = 'D:/myworkspace/dataset/CNN/train_data/test/1/frame_07_01_0105.png'

# We preprocess the image into a 4D tensor
from keras.preprocessing import image
import numpy as np

img = image.load_img(img_path, target_size=(150, 150))
img_tensor = image.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, axis=0)
# Remember that the model was trained on inputs
# that were preprocessed in the following way:
img_tensor /= 255.

# Its shape is (1, 150, 150, 3)
print(img_tensor.shape)


import matplotlib.pyplot as plt
#第一層圖片
plt.imshow(img_tensor[0])
plt.show()


from keras import models

layer_outputs=[layer.output for layer in model.layers[:8]]
activation_model=models.Model(inputs=model.input,outputs=layer_outputs)
activations = activation_model.predict(img_tensor)

first_layer_activation=activations[0]
print('第一層網絡結構大小:',first_layer_activation.shape)

#第三個通道的圖片
plt.matshow(first_layer_activation[0,:,:,3],cmap="viridis")
plt.show()
#第10個通道圖片
plt.matshow(first_layer_activation[0,:,:,30],cmap="viridis")
plt.show()

可對每個通道模型進行分析調整:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

四、源碼

本次筆記:
https://gitee.com/cungudafa/Python-notes/blob/master/CNN/CNNtest.ipynb

總結:

CNN卷積神經網絡能解決:

我們從二維圖片只能提取前景特徵的弊端,僅靠前景圖片學習訓練,容易受移動和遮擋等因素。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章