卷积神经网络 手势识别_如何构建识别手语手势的卷积神经网络
卷積神經(jīng)網(wǎng)絡(luò) 手勢(shì)識(shí)別
by Vagdevi Kommineni
通過瓦格德維·科米尼(Vagdevi Kommineni)
如何構(gòu)建識(shí)別手語(yǔ)手勢(shì)的卷積神經(jīng)網(wǎng)絡(luò) (How to build a convolutional neural network that recognizes sign language gestures)
Sign language has been a major boon for people who are hearing- and speech-impaired. But it can serve its purpose only when the other person can understand sign language. Thus it would be really nice to have a system which could convert the hand gesture image to the corresponding English letter. And so the aim of this post is to build such an American Sign Language Recognition System.
手語(yǔ)一直是聽力和言語(yǔ)障礙人士的主要福音。 但是,只有當(dāng)其他人能夠理解手語(yǔ)時(shí),它才能達(dá)到目的。 因此,擁有一個(gè)可以將手勢(shì)圖像轉(zhuǎn)換為相應(yīng)英文字母的系統(tǒng)真的很不錯(cuò)。 因此,本文的目的是建立這樣的美國(guó)手語(yǔ)識(shí)別系統(tǒng)。
Wikipedia has defined ASL as the following:
維基百科將ASL定義如下:
American Sign Language (ASL) is a natural language that serves as the predominant sign language of Deaf communities in the United States and most of Anglophone Canada.
美國(guó)手語(yǔ) ( ASL )是一種自然語(yǔ)言 ,是美國(guó)和加拿大大部分聾人社區(qū)的主要手語(yǔ) 。
First, the data: it is really important to remember the diversity of image classes with respect to influential factors like lighting conditions, zooming conditions etc. Kaggle data on ASL has all such different variants. Training on such data makes sure our model has pretty good knowledge of each class. So, let's work on the Kaggle data.
首先,數(shù)據(jù):記住影響照明條件,縮放條件等影響因素的圖像類別的多樣性非常重要。ASL上的Kaggle數(shù)據(jù)具有所有這些不同的變體。 對(duì)此類數(shù)據(jù)進(jìn)行培訓(xùn)可確保我們的模型對(duì)每個(gè)班級(jí)都有相當(dāng)好的知識(shí)。 因此,讓我們處理K aggle數(shù)據(jù) 。
The dataset consists of the images of hand gestures for each letter in the English alphabet. The images of a single class are of different variants — that is, zoomed versions, dim and bright light conditions, etc. For each class, there are as many as 3000 images. Let us consider classifying “A”, “B” and “C” images in our work for simplicity. Here are links for the full code for training and testing.
數(shù)據(jù)集由英語(yǔ)字母中每個(gè)字母的手勢(shì)圖像組成。 單個(gè)類別的圖像具有不同的變體-即縮放版本,昏暗和明亮的光照條件等。對(duì)于每個(gè)類別,最多有3000張圖像。 為了簡(jiǎn)單起見,讓我們考慮對(duì)工作中的“ A”,“ B”和“ C”圖像進(jìn)行分類。 這是培訓(xùn)和測(cè)試的完整代碼的鏈接。
We are going to build an AlexNet to achieve this classification task. Since we are training the CNN, make sure that there is the support of computational resources like GPU.
我們將構(gòu)建一個(gè)AlexNet來(lái)完成此分類任務(wù)。 由于我們正在訓(xùn)練CNN,因此請(qǐng)確保有GPU等計(jì)算資源的支持。
We start by importing the necessary modules.
我們首先導(dǎo)入必要的模塊。
import warningswarnings.filterwarnings("ignore", category=DeprecationWarning)import osimport cv2import randomimport numpy as npimport kerasfrom random import shufflefrom keras.utils import np_utilsfrom shutil import unpack_archiveprint("Imported Modules...")Download the data zip file from Kaggle data. Now, let us select the gesture images for A, B, and C and split the obtained data into training data, validation data, and test data.
從K aggle數(shù)據(jù)下載數(shù)據(jù)zip文件。 現(xiàn)在,讓我們選擇A,B和C的手勢(shì)圖像,并將獲得的數(shù)據(jù)分為訓(xùn)練數(shù)據(jù),驗(yàn)證數(shù)據(jù)和測(cè)試數(shù)據(jù)。
# data folder pathdata_folder_path = "asl_data/new" files = os.listdir(data_folder_path)# shuffling the images in the folderfor i in range(10): shuffle(files)print("Shuffled Data Files")# dictionary to maintain numerical labelsclass_dic = {"A":0,"B":1,"C":2}# dictionary to maintain countsclass_count = {'A':0,'B':0,'C':0}# training listsX = []Y = []# validation listsX_val = []Y_val = []# testing listsX_test = []Y_test = []for file_name in files: label = file_name[0] if label in class_dict: path = data_folder_path+'/'+file_name image = cv2.imread(path) resized_image = cv2.resize(image,(224,224)) if class_count[label]<2000: class_count[label]+=1 X.append(resized_image) Y.append(class_dic[label]) elif class_count[label]>=2000 and class_count[label]<2750: class_count[label]+=1 X_val.append(resized_image) Y_val.append(class_dic[label]) else: X_test.append(resized_image) Y_test.append(class_dic[label])Each image in the dataset is named according to a naming convention. The 34th image of class A is named as “A_34.jpg”. Hence, we consider only the first element of the name of the file string and check if it is of the desired class.
數(shù)據(jù)集中的每個(gè)圖像均根據(jù)命名約定進(jìn)行命名。 A類的第34張圖像命名為“ A_34.jpg”。 因此,我們僅考慮文件字符串名稱的第一個(gè)元素,并檢查它是否屬于所需的類。
Also, we are splitting the images based on counts and storing those images in the X and Y lists — X for image, and Y for the corresponding classes. Here, counts refer to the number of images we wish to put in the training, validation, and test sets respectively. So here, out of 3000 images for each class, I have put 2000 images in the training set, 750 images in the validation set, and the remaining in the test set.
另外,我們將基于計(jì)數(shù)拆分圖像并將這些圖像存儲(chǔ)在X和Y列表中-X表示圖像,Y表示對(duì)應(yīng)的類。 在這里,計(jì)數(shù)是指我們希望分別放入訓(xùn)練,驗(yàn)證和測(cè)試集中的圖像數(shù)量。 因此,這里,在每個(gè)課程的3000張圖像中,我將2000張圖像放入訓(xùn)練集中,將750張圖像放入驗(yàn)證集中,其余的放入測(cè)試集中。
Some people also prefer to split based on the total dataset (not for each class as we did here), but this doesn’t promise that all classes are learned properly. The images are read and are stored in the form of Numpy arrays in the lists.
有些人還希望基于總數(shù)據(jù)集進(jìn)行拆分(而不是像我們?cè)诖颂幠菢訉?duì)每個(gè)班級(jí)進(jìn)行拆分),但這并不能保證所有班級(jí)都能正確學(xué)習(xí)。 圖像被讀取并以Numpy數(shù)組的形式存儲(chǔ)在列表中。
Now the label lists (the Y’s) are encoded to form numerical one-hot vectors. This is done by the np_utils.to_categorical.
現(xiàn)在,標(biāo)簽列表(Y)被編碼以形成數(shù)字一熱向量。 這是由np_utils.to_categorical完成的。
# one-hot encodings of the classesY = np_utils.to_categorical(Y)Y_val = np_utils.to_categorical(Y_val)Y_test = np_utils.to_categorical(Y_test)Now, let us store these images in the form of .npy files. Basically, we create separate .npy files to store the images belonging to each set.
現(xiàn)在,讓我們以.npy文件的形式存儲(chǔ)這些圖像。 基本上,我們創(chuàng)建單獨(dú)的.npy文件來(lái)存儲(chǔ)屬于每個(gè)集合的圖像。
if not os.path.exists('Numpy_folder'): os.makedirs('Numpy_folder')np.save(npy_data_path+'/train_set.npy',X)np.save(npy_data_path+'/train_classes.npy',Y)np.save(npy_data_path+'/validation_set.npy',X_val)np.save(npy_data_path+'/validation_classes.npy',Y_val)np.save(npy_data_path+'/test_set.npy',X_test)np.save(npy_data_path+'/test_classes.npy',Y_test)print("Data pre-processing Success!")Now that we have completed the data preprocessing part, let us take a look at the full data preprocessing code here:
現(xiàn)在我們已經(jīng)完成了數(shù)據(jù)預(yù)處理部分,讓我們?cè)谶@里查看完整的數(shù)據(jù)預(yù)處理代碼:
# preprocess.pyimport warningswarnings.filterwarnings("ignore", category=DeprecationWarning)import osimport cv2import randomimport numpy as npimport kerasfrom random import shufflefrom keras.utils import np_utilsfrom shutil import unpack_archiveprint("Imported Modules...")# data folder pathdata_folder_path = "asl_data/new" files = os.listdir(data_folder_path)# shuffling the images in the folderfor i in range(10): shuffle(files)print("Shuffled Data Files")# dictionary to maintain numerical labelsclass_dic = {"A":0,"B":1,"C":2}# dictionary to maintain countsclass_count = {'A':0,'B':0,'C':0}# training listsX = []Y = []# validation listsX_val = []Y_val = []# testing listsX_test = []Y_test = []for file_name in files: label = file_name[0] if label in class_dict: path = data_folder_path+'/'+file_name image = cv2.imread(path) resized_image = cv2.resize(image,(224,224)) if class_count[label]<2000: class_count[label]+=1 X.append(resized_image) Y.append(class_dic[label]) elif class_count[label]>=2000 and class_count[label]<2750: class_count[label]+=1 X_val.append(resized_image) Y_val.append(class_dic[label]) else: X_test.append(resized_image) Y_test.append(class_dic[label])# one-hot encodings of the classesY = np_utils.to_categorical(Y)Y_val = np_utils.to_categorical(Y_val)Y_test = np_utils.to_categorical(Y_test)if not os.path.exists('Numpy_folder'): os.makedirs('Numpy_folder')np.save(npy_data_path+'/train_set.npy',X)np.save(npy_data_path+'/train_classes.npy',Y)np.save(npy_data_path+'/validation_set.npy',X_val)np.save(npy_data_path+'/validation_classes.npy',Y_val)np.save(npy_data_path+'/test_set.npy',X_test)np.save(npy_data_path+'/test_classes.npy',Y_test)print("Data pre-processing Success!")Now comes the training part! Let us start by importing the essential modules so we can construct and train the CNN AlexNet. Here it is primarily done using Keras.
現(xiàn)在是訓(xùn)練部分! 讓我們從導(dǎo)入基本模塊開始,以便我們可以構(gòu)建和訓(xùn)練CNN AlexNet。 這里主要是使用Keras完成的。
# importing from keras.optimizers import SGDfrom keras.models import Sequentialfrom keras.preprocessing import imagefrom keras.layers.normalization import BatchNormalizationfrom keras.layers import Dense, Activation, Dropout, Flatten,Conv2D, MaxPooling2Dprint("Imported Network Essentials")We next go for loading the images stored in the form of .npy:
接下來(lái),我們將加載以.npy格式存儲(chǔ)的圖像:
X_train=np.load(npy_data_path+"/train_set.npy")Y_train=np.load(npy_data_path+"/train_classes.npy")X_valid=np.load(npy_data_path+"/validation_set.npy")Y_valid=np.load(npy_data_path+"/validation_classes.npy")X_test=np.load(npy_data_path+"/test_set.npy")Y_test=np.load(npy_data_path+"/test_classes.npy")We then head towards defining the structure of our CNN. Assuming prior knowledge of the AlexNet architecture, here is the Keras code for that.
然后,我們走向定義CNN的結(jié)構(gòu)。 假設(shè)具有AlexNet架構(gòu)的先驗(yàn)知識(shí),下面是Keras的代碼。
model = Sequential()# 1st Convolutional Layermodel.add(Conv2D(filters=96, input_shape=(224,224,3), kernel_size=(11,11),strides=(4,4), padding='valid'))model.add(Activation('relu'))# Max Pooling model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisation before passing it to the next layermodel.add(BatchNormalization())# 2nd Convolutional Layermodel.add(Conv2D(filters=256, kernel_size=(11,11), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Max Poolingmodel.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisationmodel.add(BatchNormalization())# 3rd Convolutional Layermodel.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Batch Normalisationmodel.add(BatchNormalization())# 4th Convolutional Layermodel.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Batch Normalisationmodel.add(BatchNormalization())# 5th Convolutional Layermodel.add(Conv2D(filters=256, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Max Poolingmodel.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisationmodel.add(BatchNormalization())# Passing it to a dense layermodel.add(Flatten())# 1st Dense Layermodel.add(Dense(4096, input_shape=(224*224*3,)))model.add(Activation('relu'))# Add Dropout to prevent overfittingmodel.add(Dropout(0.4))# Batch Normalisationmodel.add(BatchNormalization())# 2nd Dense Layermodel.add(Dense(4096))model.add(Activation('relu'))# Add Dropoutmodel.add(Dropout(0.6))# Batch Normalisationmodel.add(BatchNormalization())# 3rd Dense Layermodel.add(Dense(1000))model.add(Activation('relu'))# Add Dropoutmodel.add(Dropout(0.5))# Batch Normalisationmodel.add(BatchNormalization())# Output Layermodel.add(Dense(24))model.add(Activation('softmax'))model.summary()The Sequential model is a linear stack of layers. We add the convolutional layers (applying filters), activation layers (for non-linearity), max-pooling layers (for computational efficiency) and batch normalization layers (to standardize the input values from the previous layer to the next layer) and the pattern is repeated five times.
Sequential模型是層的線性堆棧。 我們添加卷積層(應(yīng)用過濾器),激活層(用于非線性),最大池化層(用于計(jì)算效率)和批處理歸一化層(以標(biāo)準(zhǔn)化從上一層到下一層的輸入值)和模式重復(fù)五次。
The Batch Normalization layer was introduced in 2014 by Ioffe and Szegedy. It addresses the vanishing gradient problem by standardizing the output of the previous layer, it speeds up the training by reducing the number of required iterations, and it enables the training of deeper neural networks.
批次歸一化層由Ioffe和Szegedy于2014年引入。 它通過標(biāo)準(zhǔn)化前一層的輸出來(lái)解決消失的梯度問題,通過減少所需的迭代次數(shù)來(lái)加快訓(xùn)練速度,并且可以訓(xùn)練更深的神經(jīng)網(wǎng)絡(luò)。
At last, 3 fully-connected dense layers along with dropouts (to avoid over-fitting) are added.
最后,添加3個(gè)完全連接的密集層以及輟學(xué)(以避免過度擬合)。
To get the summarized description of the model, use model.summary().
要獲取模型的摘要說(shuō)明,請(qǐng)使用model.summary()。
The following is the code for the compilation part of the model. We define the optimization method to follow as SGD and set the parameters.
以下是該模型的編譯部分的代碼。 我們定義遵循SGD的優(yōu)化方法并設(shè)置參數(shù)。
# Compile sgd = SGD(lr=0.001)model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])checkpoint = keras.callbacks.ModelCheckpoint("Checkpoint/weights.{epoch:02d}-{val_loss:.2f}.hdf5", monitor='val_loss', verbose=0,save_best_only=False, save_weights_only=False, mode='auto', period=1)lr in SGD is the learning rate. Since this is a categorical classification, we use categorical_crossentropy as the loss function in model.compile. We set the optimizer to be sgd, the SGD object we have defined and set the evaluation metric to be accuracy.
SGD中的lr是學(xué)習(xí)率。 由于這是分類分類,因此我們將categorical_crossentropy用作model.compile的損失函數(shù)。 我們將優(yōu)化器設(shè)置為sgd , sgd定義的SGD對(duì)象,并將評(píng)估指標(biāo)設(shè)置為準(zhǔn)確性。
While using GPU, sometimes it may happen to interrupt its running. Using checkpoints is the best way to store the weights we had gotten up to the point of interruption, so that we may use them later. The first parameter is to set the place to store: save it as weights.{epoch:02d}-{val_loss:.2f}.hdf5 in the Checkpoints folder.
使用GPU時(shí),有時(shí)可能會(huì)中斷其運(yùn)行。 使用檢查點(diǎn)是存儲(chǔ)權(quán)衡到中斷點(diǎn)的權(quán)重的最佳方法,以便我們以后可以使用它們。 第一個(gè)參數(shù)是設(shè)置存儲(chǔ)位置:將其保存為weights.{epoch:02d}-{val_loss:.2f}.hdf5位于Checkpoints文件夾中。
Finally, we save the model in the json format and weights in .h5 format. These are thus saved locally in the specified folders.
最后,我們將模型保存為json格式,并將權(quán)重保存為.h5格式。 因此,這些文件將本地保存在指定的文件夾中。
# serialize model to JSONmodel_json = model.to_json()with open("Weights_Full/model.json", "w") as json_file: json_file.write(model_json)# serialize weights to HDF5model.save_weights("Weights_Full/model_weights.h5")print("Saved model to disk")Let’s look at the whole code of defining and training the network. Consider this as a separate file ‘training.py’.
讓我們看一下定義和訓(xùn)練網(wǎng)絡(luò)的整個(gè)代碼。 將此視為單獨(dú)的文件“ training.py”。
# training.pyfrom keras.optimizers import SGDfrom keras.models import Sequentialfrom keras.preprocessing import imagefrom keras.layers.normalization import BatchNormalizationfrom keras.layers import Dense, Activation, Dropout, Flatten,Conv2D, MaxPooling2Dprint("Imported Network Essentials")# loading .npy datasetX_train=np.load(npy_data_path+"/train_set.npy")Y_train=np.load(npy_data_path+"/train_classes.npy")X_valid=np.load(npy_data_path+"/validation_set.npy")Y_valid=np.load(npy_data_path+"/validation_classes.npy")X_test=np.load(npy_data_path+"/test_set.npy")Y_test=np.load(npy_data_path+"/test_classes.npy")X_test.shapemodel = Sequential()# 1st Convolutional Layermodel.add(Conv2D(filters=96, input_shape=(224,224,3), kernel_size=(11,11),strides=(4,4), padding='valid'))model.add(Activation('relu'))# Pooling model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisation before passing it to the next layermodel.add(BatchNormalization())# 2nd Convolutional Layermodel.add(Conv2D(filters=256, kernel_size=(11,11), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Poolingmodel.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisationmodel.add(BatchNormalization())# 3rd Convolutional Layermodel.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Batch Normalisationmodel.add(BatchNormalization())# 4th Convolutional Layermodel.add(Conv2D(filters=384, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Batch Normalisationmodel.add(BatchNormalization())# 5th Convolutional Layermodel.add(Conv2D(filters=256, kernel_size=(3,3), strides=(1,1), padding='valid'))model.add(Activation('relu'))# Poolingmodel.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid'))# Batch Normalisationmodel.add(BatchNormalization())# Passing it to a dense layermodel.add(Flatten())# 1st Dense Layermodel.add(Dense(4096, input_shape=(224*224*3,)))model.add(Activation('relu'))# Add Dropout to prevent overfittingmodel.add(Dropout(0.4))# Batch Normalisationmodel.add(BatchNormalization())# 2nd Dense Layermodel.add(Dense(4096))model.add(Activation('relu'))# Add Dropoutmodel.add(Dropout(0.6))# Batch Normalisationmodel.add(BatchNormalization())# 3rd Dense Layermodel.add(Dense(1000))model.add(Activation('relu'))# Add Dropoutmodel.add(Dropout(0.5))# Batch Normalisationmodel.add(BatchNormalization())# Output Layermodel.add(Dense(24))model.add(Activation('softmax'))model.summary()# (4) Compile sgd = SGD(lr=0.001)model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])checkpoint = keras.callbacks.ModelCheckpoint("Checkpoint/weights.{epoch:02d}-{val_loss:.2f}.hdf5", monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)# (5) Trainmodel.fit(X_train/255.0, Y_train, batch_size=32, epochs=50, verbose=1,validation_data=(X_valid/255.0,Y_valid/255.0), shuffle=True,callbacks=[checkpoint])# serialize model to JSONmodel_json = model.to_json()with open("Weights_Full/model.json", "w") as json_file: json_file.write(model_json)# serialize weights to HDF5model.save_weights("Weights_Full/model_weights.h5")print("Saved model to disk")When we run the training.py file, we get to see something as follows:
當(dāng)我們運(yùn)行training.py文件時(shí),我們將看到以下內(nèi)容:
For example, considering the first epoch of 12(Epoch 1/12):
例如,考慮第一個(gè)紀(jì)元12(紀(jì)元1/12):
- it took 1852s to complete that epoch 完成了那個(gè)時(shí)代花了1852年代
- the training loss was 0.2441 訓(xùn)練損失為0.2441
- accuracy was 0.9098 on the validation data 驗(yàn)證數(shù)據(jù)的準(zhǔn)確性為0.9098
- 0.0069 was the validation loss, and 驗(yàn)證損失為0.0069,并且
- 0.9969 was the validation accuracy. 驗(yàn)證準(zhǔn)確性為0.9969。
So based on these values, we know the parameters of which epochs are performing better, where to stop training, and how to tune the hyperparameter values.
因此,基于這些值,我們知道哪些時(shí)期的效果更好,在哪里停止訓(xùn)練以及如何調(diào)整超參數(shù)值的參數(shù)。
Now it’s time for testing!
現(xiàn)在該進(jìn)行測(cè)試了!
# test.pyimport warningswarnings.filterwarnings("ignore", category=DeprecationWarning) from keras.preprocessing import imageimport numpy as npfrom keras.models import model_from_jsonfrom sklearn.metrics import accuracy_score# dimensions of our imagesimage_size = 224# load the model in json formatwith open('Model/model.json', 'r') as f: model = model_from_json(f.read()) model.summary()model.load_weights('Model/model_weights.h5')model.load_weights('Weights/weights.250-0.00.hdf5')X_test=np.load("Numpy/test_set.npy")Y_test=np.load("Numpy/test_classes.npy")Y_predict = model.predict(X_test)Y_predict = [np.argmax(r) for r in Y_predict]Y_test = [np.argmax(r) for r in Y_test]print("##################")acc_score = accuracy_score(Y_test, Y_predict)print("Accuracy: " + str(acc_score))print("##################")From the above code, we load the saved model architecture and the best weights. Also, we load the .npy files (the Numpy form of the test set) and go for the prediction of these test set of images. In short, we just load the saved model architecture and assign it the learned weights.
從上面的代碼,我們加載保存的模型架構(gòu)和最佳權(quán)重。 同樣,我們加載.npy文件(測(cè)試集的Numpy形式),并預(yù)測(cè)這些圖像測(cè)試集。 簡(jiǎn)而言之,我們只是加載保存的模型架構(gòu)并為其分配學(xué)習(xí)的權(quán)重。
Now the approximator function along with the learned coefficients (weights) is ready. We just need to test it by feeding the model with the test set images and evaluating its performance on this test set. One of the famous evaluation metrics is accuracy. The accuracy is given by accuracy_score of sklearn.metrics.
現(xiàn)在,近似器函數(shù)以及學(xué)習(xí)的系數(shù)(權(quán)重)已準(zhǔn)備就緒。 我們只需要通過向模型提供測(cè)試集圖像并評(píng)估該測(cè)試集的性能來(lái)對(duì)其進(jìn)行測(cè)試。 著名的評(píng)估指標(biāo)之一是準(zhǔn)確性。 精度由accuracy_score給出 sklearn.metrics 。
Thank you for reading! Happy learning! :)
感謝您的閱讀! 學(xué)習(xí)愉快! :)
翻譯自: https://www.freecodecamp.org/news/asl-using-alexnet-training-from-scratch-cfec9a8acf84/
卷積神經(jīng)網(wǎng)絡(luò) 手勢(shì)識(shí)別
總結(jié)
以上是生活随笔為你收集整理的卷积神经网络 手势识别_如何构建识别手语手势的卷积神经网络的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怀孕梦到婆婆是胎梦吗
- 下一篇: Tensorflow框架:卷积神经网络实