文章目錄
一、前言
在手語視頻識別中,視頻序列大約有幾十甚至上百張圖片,因此手語識別數據集由萬張以上圖片組成,需要檢測大量的數據樣本。
對手語中的手勢檢測任務,可將它作爲目標檢測的一個分支,視爲分類迴歸任務。從中國手語的圖例來看,可以得到以下幾個特性:
- 手語圖像序列中,左右手有着不同的形狀軌跡信息,人手因運動而產生模糊的情況經常出現。運動中存在大量的雙手相交或接觸的情況,人手不斷進行着單手向雙手,雙手向單手之間的過渡轉換,而且具有單雙手難以區分的特點;
- 手語中的手勢伴隨着人臉,手臂等大量類膚色區域的干擾,並且經常出現手與臉之間,手與手臂之間的遮擋
- 手勢區域小卻包含豐富的信息,由於手語中手形複雜多變而且特殊手形多,但是手勢在圖片中卻總是隻有很少的像素區域,而且往往分辨率低;
- 中小詞彙量手語識別中需要用到大量(幾千個)的手語視頻序列,每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的過程
這裏放一個完整的片段:
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比例——分爲訓練集、驗證集和測試集,
目錄結構:
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)構建卷積神經網絡
-
搭建模型
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()
-
模型配置
model.compile()
優化器(loss:計算損失,這裏用的是交叉熵損失,metrics: 列表,包含評估模型在訓練和測試時的性能的指標)#模型配置 from keras import optimizers model.compile(optimizer=optimizers.RMSprop(lr=1e-4), loss='binary_crossentropy', metrics=['acc'])
-
模型大小
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)模型評估
- 結果可視化
#結果可視化
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卷積神經網絡能解決:
我們從二維圖片只能提取前景特徵的弊端,僅靠前景圖片學習訓練,容易受移動和遮擋等因素。