<jupyter_start><jupyter_text>American-Sign-Language Neste projeto, classificaremos os símbolos da língua gestual por meio da **Rede Neural Convolucional (CNN)**. Após o treinamento bem-sucedido do modelo CNN, o alfabeto correspondente de um símbolo de linguagem gestual será previsto. Avaliaremos o desempenho de classificação do nosso modelo usando as **matrizes de confusão** *normalizadas* e *não normalizadas*. Por fim, obteremos a pontuação de **precisão da classificação** do modelo CNN.  Conjunto de dadosUsando o conjunto de dados *American Sign Language* (ASL) fornecido pelo MNIST, disponível publicamente no Kaggle, avaliamos modelos para classificar os gestos das mãos para cada letra do alfabeto. Devido ao movimento envolvido nas letras J e Z, essas letras não foram incluídas no conjunto de dados. Deste modo, este conjunto de dados contém 27455 imagens de treinamento e 7172 imagens de teste, todas com formato de 28x28 pixels com valores em tons de cinza entre 0-255. Essas imagens pertencem às 24 classes do alfabeto americano, começando de A a Y (excluindo as classes das letras J (9) e Z (25), como referido anteriormente).O conjunto de dados no Kaggle está disponível no formato CSV, onde os dados de treinamento têm 27455 linhas e 785 colunas e os dados de teste têm 7172 linhas e 785 colunas. A primeira coluna do conjunto de dados representa o rótulo da classe da imagem e as 784 colunas restantes representam os 28x28 pixels. Fig. 1: Alfabeto em língua gestual americana   Tratamento e visualização dos dados  Importação de bibliotecas importantes<jupyter_code>import numpy as np
import pandas as pd
import random 
import matplotlib.pyplot as plt
import cv2
import string
from sklearn.preprocessing import LabelBinarizer
import tensorflow.keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten, Dropout
from tensorflow.keras.preprocessing.image import img_to_array
import seaborn as sns

from sklearn.metrics import confusion_matrix
from sklearn import metrics<jupyter_output><empty_output><jupyter_text>Leitura dos dados de treino e de teste dos ficheiros CSV<jupyter_code># obter os dados de treinamento
dataTrain = pd.read_csv('sign_mnist_train.csv')
# converter os rotulos dos dados de treinamento para uma matriz (rotulo)
yTrain = dataTrain['label'].values
yTrain2 = dataTrain['label'].values
# remover os rotulos dos dados de treinamento
dataTrain.drop('label', axis = 1, inplace = True)
# converter os dados de treinamento para uma matriz (rotulo + pixeis)
xTrain = dataTrain.values

# obter os dados de teste
dataTest = pd.read_csv('sign_mnist_test.csv')
# converter os rotulos dos dados de teste para uma matriz (rotulo)
yTest = dataTest['label'].values
yTest2 = dataTest['label'].values
# remover os rotulos dos dados de teste
dataTest.drop('label', axis = 1, inplace = True)
# converter os dados de teste para uma matriz (rotulo + pixeis)
xTest = dataTest.values
# verificar os dados de teste para verificar os rotulos de classe e as colunas que representam os pixeis
# dataTest.head()<jupyter_output><empty_output><jupyter_text>Especificar os rótulos de classe para as imagens<jupyter_code>class_name = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K' , 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X','Y')<jupyter_output><empty_output><jupyter_text>Histograma com o número de vezes que aparece uma letra do alfabeto, onde "A" corresponde à classe 0, "B" à classe 1 e assim sucessivamente<jupyter_code>#plt.figure(figsize = (20,8))
#plt.xlabel('classes')
#sns.countplot(x = yTrain)

plt.figure(figsize = (20,8))
plt.xlabel('classes')
sns.countplot(x = yTrain)
x_pos = np.arange(len(class_name))
plt.xticks(x_pos, class_name)<jupyter_output><empty_output><jupyter_text>Processar conjunto de dados para o treinamento"-1" especifica que esta dimensão no eixo atual deve ser calculada dinamicamente de acordo com a regra de que os elementos totais do tensor permanecem inalterados.<jupyter_code>xTrain = np.array(xTrain.reshape(-1,28,28,1))
xTest = np.array(xTest.reshape(-1,28,28,1))
print(xTrain.shape)
print(xTest.shape)<jupyter_output>(27455, 28, 28, 1)
(7172, 28, 28, 1)<jupyter_text>Converter os rótulos das classes em rótulos binários (onde "1" significa que pertence e "0" que não pertence à classe)<jupyter_code>lbTrain = LabelBinarizer()
lbTest = LabelBinarizer()
yTrain = lbTrain.fit_transform(yTrain)
yTest = lbTest.fit_transform(yTest)<jupyter_output><empty_output><jupyter_text>Visualizar algumas imagens do conjunto de dados de treinamento<jupyter_code>plt.style.use('_classic_test_patch')
fig, axs = plt.subplots(1, 5, figsize=(10, 2), sharey=True)
for i in range(5): 
    axs[i].imshow(xTrain[i].reshape(28,28),cmap='gray')
fig.suptitle('Some images from train data set')<jupyter_output><empty_output><jupyter_text>Conjunto de dados Definir o modelo CNN (Convolutional Neural Network) A partir da definição da documentação tensorflow.keras, o modelo *Sequencial* é uma stack linear de camadas. O parâmetro *kernel_size* é um inteiro que especifica o mesmo valor para todas as dimensões espaciais, ou tuplo/lista de 2 inteiros, que especifica a altura e largura da janela de convolução 2D. O parâmetro *activation* é uma função de ativação a ser aplicada. O parâmetro *input_shape* é um tensor com a forma: batch_shape + (linhas, colunas, canais), quando data_format = 'canais_last', onde é preciso usar as dimensões da imagem de entrada.A camada de entrada do modelo obterá imagens de tamanho (28,28,1) onde 28,28 são a altura e a largura da imagem, respetivamente, enquanto 1 representa o canal de cor da imagem para tons de cinza.A camada de saída do modelo terá 24 neurónios para 24 letras diferentes, e a função de ativação será *softmax*, pois é um problema de classificação multiclasse.A primeira camada oculta é composta por vários nós, cada um dos quais tem uma soma ponderada dos 784 valores de entrada. A soma ponderada das entradas é então inserida numa função de ativação ReLU (Rectified Linear Unit). o ReLU produzirá 0 quando a entrada for negativa, mas não mudará a entrada de outra forma. As saídas do ReLU servirão como entradas para a próxima camada oculta na rede.À medida que os dados continuam a se mover pelas camadas ocultas, a rede neural tenta extrair mais recursos abstratos.Depois que os dados passam pelas camadas Convolution (*Conv2D*) e MaxPool (*MaxPooling2D*) da rede neural, eles entram nas camadas *Flatten* e *Dense*. Essas camadas são responsáveis por reduzir os dados a uma dimensão e identificar a classe de uma imagem.Observe que o Dropout foi definido como 0,2 no final. No backend, ele essencialmente reduz o overfitting, ou seja, o fenômeno quando o modelo tem um desempenho muito bom nos dados de treinamento, mas falha miseravelmente com os dados de teste.Depois que a arquitetura da CNN foi definida, tentamos otimizar o desempenho do modelo selecionando um valor apropriado para o número de épocas. Anteriormente, mencionamos que cada nó obtém uma soma ponderada de suas entradas. Os pesos aplicados a cada entrada são aprendidos durante o processo de treinamento e atualizados a cada época. Uma época é uma única passagem por todos os dados de treinamento. Na primeira época, a rede neural estima um valor para cada peso. Para cada época subsequente, a rede neural atualiza esses pesos com valores que reduzem a perda geral. Geralmente, mais épocas resultam em classificadores mais precisos; no entanto, mais épocas também produzem modelos mais complexos.<jupyter_code>model = Sequential()
# camada de convolução 1
model.add(Conv2D(64, kernel_size=(3,3), activation = 'relu', input_shape=(28, 28 ,1) ))
model.add(MaxPooling2D(pool_size = (2, 2)))

# camada de convolução 2
model.add(Conv2D(64, kernel_size = (3, 3), activation = 'relu'))
model.add(MaxPooling2D(pool_size = (2, 2)))
model.add(Dropout(0.20))

# camada de convolução 3
model.add(Conv2D(64, kernel_size = (3, 3), activation = 'relu'))
model.add(MaxPooling2D(pool_size = (2, 2)))
model.add(Dropout(0.20))



model.add(Flatten())
model.add(Dense(128, activation = 'relu'))
model.add(Dropout(0.20))
model.add(Dense(24, activation = 'softmax'))<jupyter_output><empty_output><jupyter_text>Compilar o modelo de CNN (Convolutional Neural Network)Depois do CNN pronto, é preciso treinar o modelo alimentando o conjunto de treinamento. Existem vários otimizadores que podem ser usados, mas foi escolhido o *adam*.Depois que a arquitetura da CNN foi definida, tentamos otimizar o desempenho do modelo selecionando um valor apropriado para o número de épocas. Cada nó obtém uma soma ponderada de suas entradas. Os pesos aplicados a cada entrada são aprendidos durante o processo de treinamento e atualizados a cada epoch (época). Uma época é uma única passagem por todos os dados de treinamento. Na primeira época, a rede neural estima um valor para cada peso. Para cada época subsequente, a rede neural atualiza esses pesos com valores que reduzem a perda geral. Geralmente, mais épocas resultam em classificadores mais precisos; no entanto, mais épocas também produzem modelos mais complexos e levam mais tempo de treinamento.<jupyter_code>model.compile(loss = tensorflow.keras.losses.categorical_crossentropy, optimizer=tensorflow.keras.optimizers.Adam(), metrics=['accuracy'])
# Let's use 15% of our training dataset to validate our model

num_rows = xTrain.shape[0]
val_percent = 0.15
val_size = int(num_rows * val_percent) #4118 para validar os dados
train_size = num_rows - val_size  #23337 para dados de traino

xtrain_ds = xTrain[:train_size] #23337
xval_ds = xTrain[train_size:] #4118
ytrain_ds = yTrain[:train_size] #23337
yval_ds = yTrain[train_size:] #4118<jupyter_output><empty_output><jupyter_text>Treinar o modelo CNN (Convolutional Neural Network)<jupyter_code>history = model.fit(xtrain_ds, ytrain_ds, validation_data = (xval_ds, yval_ds), epochs=100, batch_size=128)
model.save('sign_language')
model.summary()
#model = tensorflow.keras.models.load_model('sign_language')<jupyter_output>INFO:tensorflow:Assets written to: sign_language/assets
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_12 (Conv2D)           (None, 26, 26, 64)        640       
_________________________________________________________________
max_pooling2d_12 (MaxPooling (None, 13, 13, 64)        0         
_________________________________________________________________
conv2d_13 (Conv2D)           (None, 11, 11, 64)        36928     
_________________________________________________________________
max_pooling2d_13 (MaxPooling (None, 5, 5, 64)          0         
_________________________________________________________________
dropout_12 (Dropout)         (None, 5, 5, 64)          0         
_________________________________________________________________
conv2d_14 (Conv2D)           (None, 3, 3, 64)          36928    [...]<jupyter_text>Visualizar o desempenho do treinamento do modelo CNNDepois do treinamento acabar, desenhou-se a variação de precisão com a época para visualizar como nosso modelo está melhorando a cada época.<jupyter_code>plt.style.use('default')
plt.figure(figsize = (10,6))

plt.subplot(2,2,1)
plt.plot(history.history['loss'], label = 'Loss')
plt.plot(history.history['val_loss'], label = 'val_Loss')
plt.legend()
plt.grid()
plt.title('Evolução de perda (Loss Evolution)')

plt.subplot(2,2,2)
plt.plot(history.history['accuracy'], label = 'Accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.legend()
plt.grid()
plt.title('Evolução de precisão (Accurary Evolution)')<jupyter_output><empty_output><jupyter_text>Usar o modelo CNN treinado para fazer previsões sobre os dados de teste invisíveis<jupyter_code>predicted_classes = model.predict_classes(xTest)
pred2 = np.zeros(shape=(7172,))

for i in range(7172):
    if(predicted_classes[i]>=9):
        pred2[i] = predicted_classes[i] + 1
    else:
        pred2[i] = predicted_classes[i]
pred2 = pred2.astype(int)<jupyter_output><empty_output><jupyter_text>Visualização das previsoes dos rótulos das classes para as imagens de teste do modelo da CNN<jupyter_code>fig, axes = plt.subplots(5, 5, figsize = (12,12)) 
axes = axes.ravel() 
for i in np.arange (0, 5*5):
    if (predicted_classes[i] >= 9):
        axes[i].imshow(xTest[i].reshape(28,28)) 
        axes[i].set_title("Prediction Class = {0} \n True Class = {1}".format(pred2[i], yTest2[i])) 
        axes[i].axis('off') 
    else:
        axes[i].imshow(xTest[i].reshape(28,28)) 
        axes[i].set_title("Prediction Class = {0} \n True Class = {1}".format(pred2[i], yTest2[i])) 
        axes[i].axis('off') 
plt.subplots_adjust(wspace = 0.5)<jupyter_output><empty_output><jupyter_text>Visualização do relatório completo de classificação, usando matrizes de confusão normalizadas e não nor<jupyter_code># A matriz de confusão precisa de rótulos e previsões como dígitos únicos, não como vetores codificados por um ponto
predicted_classes = model.predict_classes(xTest, batch_size=128, verbose=0)
rounded_labels=np.argmax(yTest, axis=1)
cm = metrics.confusion_matrix(rounded_labels, predicted_classes)<jupyter_output><empty_output><jupyter_text>Definir a função para o gráfico da matriz de confusão<jupyter_code>def plot_confusion_matrix(y_true, y_pred, classes, normalize=False, title=None, cmap=plt.cm.Blues):
    if not title:
        if normalize:
            title = 'Normalized confusion matrix'
        else:
            title = 'Confusion matrix, without normalization'

    # matriz de confusao
    cm = confusion_matrix(y_true, y_pred)
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    # visualizacao
    fig, ax = plt.subplots(figsize=(10, 10))
    im = ax.imshow(cm, interpolation='nearest', cmap=cmap)
    ax.figure.colorbar(im, ax=ax)
    ax.set(xticks=np.arange(cm.shape[1]), yticks=np.arange(cm.shape[0]), xticklabels=classes, yticklabels=classes, title=title, ylabel='True label', xlabel='Predicted label')

    # girar os rótulos e definir o alinhamento
    plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor")
    
    # loop sobre dimensoes de dados e criar anotacoes de texto
    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            ax.text(j, i, format(cm[i, j], fmt),
                    ha="center", va="center",
                    color="white" if cm[i, j] > thresh else "black")
    fig.tight_layout()
    return ax

np.set_printoptions(precision=2)<jupyter_output><empty_output><jupyter_text>Matriz de confusão não normalizada<jupyter_code>plt.figure(figsize=(20,20))
plot_confusion_matrix(rounded_labels, predicted_classes, classes = class_name, title='Non-Normalized Confusion matrix')
plt.show()<jupyter_output>Confusion matrix, without normalization<jupyter_text>Matriz de confusão normalizada<jupyter_code>plt.figure(figsize=(35,35))
plot_confusion_matrix(rounded_labels, predicted_classes, classes = class_name, normalize=True, title='Normalized Confusion matrix')
plt.show()<jupyter_output>Normalized confusion matrix<jupyter_text>Pontuação média de precisão da classificação<jupyter_code>from sklearn.metrics import accuracy_score
acc_score = accuracy_score(rounded_labels, predicted_classes)
print('Accuracy Score = ',acc_score) 
#Accuracy Score =  0.9599832682654769  100 epo _ 0,2 drop
#Accuracy Score =  0.954127161182376 -  50 epo _ 0,2 drop
#Accuracy Score =  0.9421360847741216 - 20 epo _ 0,2 drop
#Accuracy Score =  0.34313998884551034 - 20 epo_ 0,5 drop
#Accuracy Score =  0.899888455103179 - 50 epos _ 0,5 drop
#Accuracy Score =  0.8467651979921919 - 20 epo _ 0,0 drop
#Accuracy Score =  0.8931957612939208 - 50 epo _ 00 drop<jupyter_output>Accuracy Score =  0.9354433909648634<jupyter_text>O modelo treinado obteve uma precisão de cerca de 95,16%. Isso é muito bom. No entanto, é possível obter uma precisão muito maior ajustando os parâmetros que foram usados.Esta percentagem significa que, para este modelo poder reconhecer corretamente a qual alfabeto um gesto de mão se refere na linguagem de sinais quase 92 vezes para cada 100 imagens! Ou seja, dada uma imagem 28x28 de um gesto de mão como entrada, é altamente provável que nosso modelo identifique o que é corretamente.Para entender melhor os pontos fortes e fracos desse modelo, criamos uma matriz de confusão.<jupyter_code>def classify(image):
    image = cv2.resize(image, (28, 28))
    image = image.astype("float") / 255.0
    image = img_to_array(image)
    image = np.expand_dims(image, axis = 0)
    proba = model.predict(image)
    idx = np.argmax(proba)
    return class_name[idx]
classify(xTrain[2]*255)
print(yTrain2[0])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09301369058111522, 'fraction_numerical': 0.0324343380927199, 'mean_word_length': 5.227588730332967, 'pattern_counts': {'":': 0, '<': 72, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '380407', 'license': 'MIT', 'n_tokens_mistral': 6177, 'n_tokens_neox': 5734, 'n_words': 1836, 'path': 'Project1/.ipynb_checkpoints/mainCNN-checkpoint.ipynb', 'repo_name': 'renatovalente5/AA-Projs', 'size': '17019'}