de Vagdevi Kommineni

Cum să construiți o rețea neuronală convoluțională care să recunoască gesturile limbajului semnelor

Limbajul semnelor a fost un avantaj major pentru persoanele cu deficiențe de auz și de vorbire. Dar își poate îndeplini scopul numai atunci când cealaltă persoană poate înțelege limbajul semnelor. Astfel, ar fi foarte frumos să ai un sistem care să poată converti imaginea gestului mâinii în litera engleză corespunzătoare. Astfel, scopul acestei postări este de a construi un astfel de sistem de recunoaștere a limbajului semnelor american.

Cum sa construiesti o retea neuronala convolutionala care sa recunoasca

Wikipedia a definit ASL astfel:

Limbajul semnelor americane (ASL) este un limbaj natural care servește ca predominant limbajul semnelor de Comunități surde în Statele Unite și în cea mai mare parte a Canadei anglofone.

În primul rând, datele: este cu adevărat important să ne amintim diversitatea claselor de imagini cu privire la factori influenți, cum ar fi condițiile de iluminare, condițiile de zoom etc. Kaggle date pe ASL are toate aceste variante diferite. Instruirea asupra acestor date asigură faptul că modelul nostru are cunoștințe destul de bune despre fiecare clasă. Deci, să lucrăm la Kaggle date.

Setul de date constă din imagini cu gesturi de mână pentru fiecare literă din alfabetul englez. Imaginile unei singure clase sunt de diferite variante – adică versiuni mărite, condiții de lumină slabă și strălucitoare etc. Pentru fiecare clasă, există până la 3000 de imagini. Să luăm în considerare clasificarea imaginilor „A”, „B” și „C” în lucrarea noastră pentru simplitate. Iată linkuri pentru codul complet pentru Instruire și testarea.

1611543246 120 Cum sa construiesti o retea neuronala convolutionala care sa recunoasca
O imagine pentru litera „A” din setul de date

Vom construi un AlexNet pentru a realiza această sarcină de clasificare. Întrucât pregătim CNN, asigurați-vă că există suport pentru resurse de calcul precum GPU.

Începem prin importul modulelor necesare.

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_archive
print("Imported Modules...")

Descărcați fișierul zip de date de la Kaggle date. Acum, să selectăm imaginile gestuale pentru A, B și C și să împărțim datele obținute în date de antrenament, date de validare și date de testare.

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

Fiecare imagine din setul de date este denumită conform unei convenții de denumire. A 34-a imagine a clasei A este denumită „A_34.jpg”. Prin urmare, luăm în considerare numai primul element al numelui șirului de fișiere și verificăm dacă este din clasa dorită.

De asemenea, împărțim imaginile pe baza numărărilor și stocăm aceste imagini în listele X și Y – X pentru imagine și Y pentru clasele corespunzătoare. Aici, numărările se referă la numărul de imagini pe care dorim să le punem în seturile de antrenament, validare și test. Așadar, aici, din 3000 de imagini pentru fiecare clasă, am pus 2000 de imagini în setul de antrenament, 750 de imagini în setul de validare și restul în setul de testare.

Unii oameni preferă, de asemenea, să se împartă pe baza setului de date total (nu pentru fiecare clasă așa cum am făcut aici), dar acest lucru nu promite că toate clasele sunt învățate corect. Imaginile sunt citite și sunt stocate sub formă de matrice Numpy în liste.

Acum listele de etichete (Y-urile) sunt codificate pentru a forma vectori numerici one-hot. Acest lucru este realizat de 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)

Acum, permiteți-ne să stocăm aceste imagini sub formă de fișiere .npy. Practic, creăm fișiere .npy separate pentru a stoca imaginile aparținând fiecărui set.

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

Acum că am finalizat partea de preprocesare a datelor, să aruncăm o privire asupra codului complet de preprocesare a datelor aici:

# preprocess.py
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_archive
print("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!")

Acum vine partea de instruire! Să începem prin importul modulelor esențiale, astfel încât să putem construi și instrui CNN AlexNet. Aici se face în primul rând folosind 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, MaxPooling2D
print("Imported Network Essentials")

Urmăm să încărcăm imaginile stocate sub forma .npy:

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

Ne îndreptăm apoi spre definirea structurii CNN-ului nostru. Presupunând cunoștințe prealabile despre AlexNet arhitectură, aici este codul Keras pentru asta.

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

Sequential modelul este un teanc liniar de straturi. Adăugăm straturile convoluționale (aplicarea filtrelor), straturile de activare (pentru neliniaritate), straturile de grupare maximă (pentru eficiența de calcul) și straturile de normalizare a lotului (pentru a standardiza valorile de intrare de la stratul anterior la stratul următor) și model se repetă de cinci ori.

Stratul Batch Normalization a fost introdus în 2014 de Ioffe și Szegedy. Abordează problema gradientului de dispariție prin standardizarea ieșirii stratului anterior, accelerează antrenamentul prin reducerea numărului de iterații necesare și permite formarea rețelelor neuronale mai profunde.

În cele din urmă, se adaugă 3 straturi dense complet conectate, împreună cu dropouts (pentru a evita supra-montarea).

Pentru a obține descrierea rezumată a modelului, utilizați model.summary ().

Următorul este codul pentru partea de compilare a modelului. Definim metoda de optimizare de urmat ca SGD și setăm parametrii.

# 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 în SGD este rata de învățare. Deoarece aceasta este o clasificare categorică, folosim categorical_crossentropy ca funcție de pierdere în model.compile. Am setat optimizatorul să fie sgd, obiectul SGD l-am definit și setat metrica de evaluare să fie exactă.

În timp ce utilizați GPU, uneori se poate întâmpla să întrerupă funcționarea acestuia. Folosirea punctelor de control este cel mai bun mod de a stoca greutățile pe care le-am ajuns până la întrerupere, astfel încât să le putem folosi mai târziu. Primul parametru este să setați locul de stocare: salvați-l ca weights.{epoch:02d}-{val_loss:.2f}.hdf5 în folderul Puncte de control.

În cele din urmă, salvăm modelul în format json și greutățile în format .h5. Acestea sunt astfel salvate local în folderele specificate.

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

Să ne uităm la întregul cod de definire și formare a rețelei. Luați în considerare acest lucru ca un fișier separat „training.py”.

# training.py
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, MaxPooling2D
print("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.shape
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'))# 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")

Când rulăm fișierul training.py, vom vedea ceva după cum urmează:

1611543247 173 Cum sa construiesti o retea neuronala convolutionala care sa recunoasca

De exemplu, luând în considerare prima epocă a 12 (Epoca 1/12):

  • a fost nevoie de 1852 pentru a finaliza acea epocă
  • pierderea antrenamentului a fost de 0,2441
  • precizia a fost de 0,9098 la datele de validare
  • 0,0069 a fost pierderea validării și
  • 0,9969 a fost precizia validării.

Deci, pe baza acestor valori, cunoaștem parametrii epocilor care au performanțe mai bune, unde să oprim antrenamentul și cum să reglați valorile hiperparametrului.

Acum este timpul pentru teste!

# test.py
import 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("##################")

Din codul de mai sus, încărcăm arhitectura modelului salvat și cele mai bune greutăți. De asemenea, încărcăm fișierele .npy (forma Numpy a setului de testare) și mergem pentru predicția acestor seturi de testare a imaginilor. Pe scurt, încărcăm doar arhitectura modelului salvat și îi atribuim greutățile învățate.

Acum funcția aproximator împreună cu coeficienții învățați (greutăți) este gata. Trebuie doar să îl testăm alimentând modelul cu imaginile setului de testare și evaluând performanța acestuia pe acest set de testare. Una dintre faimoasele valori de evaluare este acuratețea. Precizia este dată de accuracy_score de sklearn.metrics.

Mulțumesc că ai citit! Învățare fericită! 🙂