Lab08 - Redes Neurais - CNN parte2
1. Carregando Bibliotecas¶
from keras.datasets import cifar10
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential,load_model
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, AveragePooling2D
from keras.layers import BatchNormalization
#from keras.utils import np_utils
from keras.utils import to_categorical
#from keras.utils import plot_model
from keras.utils import plot_model
import tensorflow as tf
Inicializa o Google Drive. É necessário entrar com as credenciais do Gmail
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive
2. Carregando o dataset pré-embaralhado de treinamento bem como os dados de teste¶
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170498071/170498071 [==============================] - 4s 0us/step
print('Train: X=%s, y=%s' % (x_train.shape, y_train.shape))
print('Test: X=%s, y=%s' % (x_test.shape, y_test.shape))
# plot first few images
for i in range(9):
# define subplot
plt.subplot(330 + 1 + i)
# plot raw pixel data
plt.imshow(x_train[i])
# show the figure
plt.show()
Train: X=(50000, 32, 32, 3), y=(50000, 1) Test: X=(10000, 32, 32, 3), y=(10000, 1)
3. Redimensionando as imagens e dividindo cada pixel em cada imagem por 255¶
x_train = x_train.astype('float32')/255
x_test = x_test.astype('float32')/255
4. Dividindo o dataset em treinamento, teste e validação¶
"One-hot encoding" aplicado aos rótulos
num_classes = len(np.unique(y_train))
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)
y_train
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 1.], [0., 0., 0., ..., 0., 0., 1.], ..., [0., 0., 0., ..., 0., 0., 1.], [0., 1., 0., ..., 0., 0., 0.], [0., 1., 0., ..., 0., 0., 0.]], dtype=float32)
num_classes
10
divindo dataset de treinamento em treinamento, teste e validação - Apenas para exemplo em um ambiente real as amostras devem ser seleciondas de forma aleatória
(x_train, x_valid) = x_train[5000:], x_train[:5000]
(y_train, y_valid) = y_train[5000:], y_train[:5000]
Impressão da forma do conjunto de treino
print('x_train shape:', x_train.shape)
x_train shape: (45000, 32, 32, 3)
print('x_valid shape:', x_valid.shape)
x_valid shape: (5000, 32, 32, 3)
Impressão do número de imagens nos datasets de treinamento, teste e validação
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
print(x_valid.shape[0], 'validation samples')
45000 train samples 10000 test samples 5000 validation samples
5. Definindo a arquitetura do modelo (IMPORTANTE!)¶
Use camadas convolucionais de tamanho progressivamente crescente: Utilize múltiplas camadas convolucionais com um número crescente de filtros (por exemplo, 32, 64, 128). Isso ajuda a capturar características mais complexas nas imagens à medida que se aprofunda na rede.
Máximo de camadas de "pooling" (2x2): Insira camadas de pooling (máximo pooling) após grupos de camadas convolucionais para reduzir as dimensões espaciais da entrada (por exemplo, 2x2 pooling). Isso ajuda a reduzir a complexidade computacional e controlar o overfitting.
Camadas totalmente conectadas: Adicione uma ou mais camadas totalmente conectadas (fully connected layers) após as camadas convolucionais e de pooling para combinar as características extraídas e realizar a classificação.
Última camada totalmente conectada com 10 saídas (10 classes de categoria de imagem): A última camada da rede deve ser uma camada totalmente conectada com 10 neurônios (unidades) de saída, correspondendo às 10 classes de imagem no seu problema de classificação. Use a função de ativação softmax para obter as probabilidades das classes.
"Dropout" de 0,2-0,5: Aplique a técnica de Dropout entre as camadas, especialmente nas camadas totalmente conectadas, com uma taxa de dropout entre 0,2 e 0,5. Isso ajuda a prevenir overfitting, desligando aleatoriamente neurônios durante o treinamento.
"BatchNormalization" após convolução: Utilize camadas de Batch Normalization após as camadas convolucionais para normalizar as ativações da camada anterior. Isso ajuda a acelerar o treinamento e a estabilizar a rede neural.
## primeira tentativa
model = Sequential()
model.add(Conv2D(filters=128, kernel_size=3, activation='relu', input_shape=(32, 32, 3), padding='same'))
model.add(Conv2D(filters=128, kernel_size=3, activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=128, kernel_size=3, activation='relu'))
model.add(Conv2D(filters=128, kernel_size=3, activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
## Segunda tentativa
# from keras.layers import BatchNormalization
# model = Sequential()
# model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu', input_shape=(32, 32, 3), padding='same'))
# model.add(BatchNormalization())
# model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu', padding='same'))
# model.add(BatchNormalization())
# model.add(MaxPooling2D(pool_size=(2,2)))
# model.add(Dropout(0.3))
# model.add(Conv2D(64, (3,3), padding='same', activation='relu'))
# model.add(BatchNormalization())
# model.add(Conv2D(64, (3,3), padding='same', activation='relu'))
# model.add(BatchNormalization())
# model.add(MaxPooling2D(pool_size=(2,2)))
# model.add(Dropout(0.5))
# model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
# model.add(BatchNormalization())
# model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
# model.add(BatchNormalization())
# model.add(MaxPooling2D(pool_size=(2,2)))
# model.add(Dropout(0.5))
# model.add(Flatten())
# model.add(Dense(128, activation='relu'))
# model.add(BatchNormalization())
# model.add(Dropout(0.5))
# model.add(Dense(num_classes, activation='softmax'))
Tentem executar a rede configurando outras funções de ativação (como visto em nossa Aula 3) mais informações em https://keras.io/activations/
plot_model(model, to_file='cnn-CIFAR10.png', show_shapes=True, show_layer_names=True)
6. Compilando o modelo¶
Compilando o modelo escolhendo como se dará nossa perda, otimização e métricas (parâmetros do Keras)
- mais informações em https://keras.io/losses/
- mais informações em https://keras.io/optimizers/
- mais informações em https://keras.io/metrics/
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
7. Treinando o modelo¶
Treinar modelos de aprendizado profundo pode ser uma tarefa demorada, especialmente para modelos complexos e conjuntos de dados grandes. Para garantir que você não perca o progresso e consiga restaurar o melhor modelo encontrado durante o treinamento, o Keras oferece a callback ModelCheckpoint. Esta ferramenta permite salvar o modelo atual após cada época, ou quando uma métrica específica melhora, facilitando a recuperação do melhor modelo
from keras.callbacks import ModelCheckpoint
O keras passa a salvar o melhor modelo pela acurácia de validação
checkpointer = ModelCheckpoint(filepath='/content/drive/My Drive/checkpoints/modelocifar.h5', verbose=1, save_best_only=True, monitor='val_accuracy') #
hist = model.fit(x_train, y_train, batch_size=100, epochs=30, validation_data=(x_valid, y_valid), callbacks=[checkpointer], verbose=1, shuffle=True)
Epoch 1/30 450/450 [==============================] - ETA: 0s - loss: 1.8334 - accuracy: 0.3789 Epoch 1: val_accuracy improved from -inf to 0.33460, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 14s 18ms/step - loss: 1.8334 - accuracy: 0.3789 - val_loss: 2.0108 - val_accuracy: 0.3346 Epoch 2/30 448/450 [============================>.] - ETA: 0s - loss: 1.2611 - accuracy: 0.5463 Epoch 2: val_accuracy improved from 0.33460 to 0.62680, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 9s 19ms/step - loss: 1.2608 - accuracy: 0.5466 - val_loss: 1.0417 - val_accuracy: 0.6268 Epoch 3/30 450/450 [==============================] - ETA: 0s - loss: 1.0718 - accuracy: 0.6208 Epoch 3: val_accuracy improved from 0.62680 to 0.66700, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 7s 16ms/step - loss: 1.0718 - accuracy: 0.6208 - val_loss: 0.9174 - val_accuracy: 0.6670 Epoch 4/30 447/450 [============================>.] - ETA: 0s - loss: 0.9540 - accuracy: 0.6639 Epoch 4: val_accuracy improved from 0.66700 to 0.68700, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 17ms/step - loss: 0.9543 - accuracy: 0.6639 - val_loss: 0.8978 - val_accuracy: 0.6870 Epoch 5/30 449/450 [============================>.] - ETA: 0s - loss: 0.8712 - accuracy: 0.6943 Epoch 5: val_accuracy did not improve from 0.68700 450/450 [==============================] - 7s 16ms/step - loss: 0.8711 - accuracy: 0.6942 - val_loss: 0.9451 - val_accuracy: 0.6798 Epoch 6/30 448/450 [============================>.] - ETA: 0s - loss: 0.8112 - accuracy: 0.7161 Epoch 6: val_accuracy improved from 0.68700 to 0.71700, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.8113 - accuracy: 0.7161 - val_loss: 0.8033 - val_accuracy: 0.7170 Epoch 7/30 448/450 [============================>.] - ETA: 0s - loss: 0.7626 - accuracy: 0.7341 Epoch 7: val_accuracy improved from 0.71700 to 0.76720, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.7623 - accuracy: 0.7342 - val_loss: 0.6699 - val_accuracy: 0.7672 Epoch 8/30 450/450 [==============================] - ETA: 0s - loss: 0.7229 - accuracy: 0.7507 Epoch 8: val_accuracy did not improve from 0.76720 450/450 [==============================] - 7s 16ms/step - loss: 0.7229 - accuracy: 0.7507 - val_loss: 0.9428 - val_accuracy: 0.6904 Epoch 9/30 450/450 [==============================] - ETA: 0s - loss: 0.6865 - accuracy: 0.7623 Epoch 9: val_accuracy did not improve from 0.76720 450/450 [==============================] - 8s 17ms/step - loss: 0.6865 - accuracy: 0.7623 - val_loss: 0.7274 - val_accuracy: 0.7484 Epoch 10/30 448/450 [============================>.] - ETA: 0s - loss: 0.6619 - accuracy: 0.7719 Epoch 10: val_accuracy improved from 0.76720 to 0.79100, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.6614 - accuracy: 0.7721 - val_loss: 0.6355 - val_accuracy: 0.7910 Epoch 11/30 447/450 [============================>.] - ETA: 0s - loss: 0.6306 - accuracy: 0.7842 Epoch 11: val_accuracy improved from 0.79100 to 0.80300, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.6310 - accuracy: 0.7840 - val_loss: 0.5668 - val_accuracy: 0.8030 Epoch 12/30 447/450 [============================>.] - ETA: 0s - loss: 0.6087 - accuracy: 0.7903 Epoch 12: val_accuracy did not improve from 0.80300 450/450 [==============================] - 8s 17ms/step - loss: 0.6090 - accuracy: 0.7903 - val_loss: 0.5881 - val_accuracy: 0.8002 Epoch 13/30 449/450 [============================>.] - ETA: 0s - loss: 0.5870 - accuracy: 0.7985 Epoch 13: val_accuracy improved from 0.80300 to 0.81220, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.5869 - accuracy: 0.7985 - val_loss: 0.5339 - val_accuracy: 0.8122 Epoch 14/30 449/450 [============================>.] - ETA: 0s - loss: 0.5685 - accuracy: 0.8063 Epoch 14: val_accuracy improved from 0.81220 to 0.82560, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 17ms/step - loss: 0.5687 - accuracy: 0.8062 - val_loss: 0.5192 - val_accuracy: 0.8256 Epoch 15/30 448/450 [============================>.] - ETA: 0s - loss: 0.5509 - accuracy: 0.8112 Epoch 15: val_accuracy improved from 0.82560 to 0.82700, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 17ms/step - loss: 0.5516 - accuracy: 0.8111 - val_loss: 0.5204 - val_accuracy: 0.8270 Epoch 16/30 450/450 [==============================] - ETA: 0s - loss: 0.5372 - accuracy: 0.8141 Epoch 16: val_accuracy did not improve from 0.82700 450/450 [==============================] - 8s 17ms/step - loss: 0.5372 - accuracy: 0.8141 - val_loss: 0.5340 - val_accuracy: 0.8150 Epoch 17/30 448/450 [============================>.] - ETA: 0s - loss: 0.5219 - accuracy: 0.8201 Epoch 17: val_accuracy improved from 0.82700 to 0.83160, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.5218 - accuracy: 0.8202 - val_loss: 0.4938 - val_accuracy: 0.8316 Epoch 18/30 450/450 [==============================] - ETA: 0s - loss: 0.5073 - accuracy: 0.8267 Epoch 18: val_accuracy improved from 0.83160 to 0.83600, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 17ms/step - loss: 0.5073 - accuracy: 0.8267 - val_loss: 0.4806 - val_accuracy: 0.8360 Epoch 19/30 450/450 [==============================] - ETA: 0s - loss: 0.5002 - accuracy: 0.8286 Epoch 19: val_accuracy did not improve from 0.83600 450/450 [==============================] - 7s 16ms/step - loss: 0.5002 - accuracy: 0.8286 - val_loss: 0.5290 - val_accuracy: 0.8166 Epoch 20/30 450/450 [==============================] - ETA: 0s - loss: 0.4842 - accuracy: 0.8338 Epoch 20: val_accuracy improved from 0.83600 to 0.84180, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.4842 - accuracy: 0.8338 - val_loss: 0.4589 - val_accuracy: 0.8418 Epoch 21/30 449/450 [============================>.] - ETA: 0s - loss: 0.4767 - accuracy: 0.8372 Epoch 21: val_accuracy did not improve from 0.84180 450/450 [==============================] - 7s 16ms/step - loss: 0.4765 - accuracy: 0.8373 - val_loss: 0.4804 - val_accuracy: 0.8394 Epoch 22/30 450/450 [==============================] - ETA: 0s - loss: 0.4654 - accuracy: 0.8406 Epoch 22: val_accuracy improved from 0.84180 to 0.84900, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.4654 - accuracy: 0.8406 - val_loss: 0.4492 - val_accuracy: 0.8490 Epoch 23/30 448/450 [============================>.] - ETA: 0s - loss: 0.4577 - accuracy: 0.8414 Epoch 23: val_accuracy did not improve from 0.84900 450/450 [==============================] - 7s 17ms/step - loss: 0.4577 - accuracy: 0.8414 - val_loss: 0.5467 - val_accuracy: 0.8178 Epoch 24/30 447/450 [============================>.] - ETA: 0s - loss: 0.4514 - accuracy: 0.8440 Epoch 24: val_accuracy did not improve from 0.84900 450/450 [==============================] - 7s 16ms/step - loss: 0.4516 - accuracy: 0.8438 - val_loss: 0.4474 - val_accuracy: 0.8462 Epoch 25/30 448/450 [============================>.] - ETA: 0s - loss: 0.4457 - accuracy: 0.8461 Epoch 25: val_accuracy did not improve from 0.84900 450/450 [==============================] - 8s 17ms/step - loss: 0.4460 - accuracy: 0.8460 - val_loss: 0.4541 - val_accuracy: 0.8456 Epoch 26/30 447/450 [============================>.] - ETA: 0s - loss: 0.4319 - accuracy: 0.8517 Epoch 26: val_accuracy improved from 0.84900 to 0.85200, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 18ms/step - loss: 0.4315 - accuracy: 0.8518 - val_loss: 0.4302 - val_accuracy: 0.8520 Epoch 27/30 447/450 [============================>.] - ETA: 0s - loss: 0.4217 - accuracy: 0.8535 Epoch 27: val_accuracy improved from 0.85200 to 0.85920, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 8s 17ms/step - loss: 0.4219 - accuracy: 0.8536 - val_loss: 0.4242 - val_accuracy: 0.8592 Epoch 28/30 449/450 [============================>.] - ETA: 0s - loss: 0.4214 - accuracy: 0.8552 Epoch 28: val_accuracy did not improve from 0.85920 450/450 [==============================] - 7s 16ms/step - loss: 0.4215 - accuracy: 0.8552 - val_loss: 0.4665 - val_accuracy: 0.8438 Epoch 29/30 447/450 [============================>.] - ETA: 0s - loss: 0.4081 - accuracy: 0.8589 Epoch 29: val_accuracy improved from 0.85920 to 0.86180, saving model to /content/drive/My Drive/checkpoints/modelocifar_FIAP_Shift.hdf5 450/450 [==============================] - 9s 19ms/step - loss: 0.4086 - accuracy: 0.8589 - val_loss: 0.4131 - val_accuracy: 0.8618 Epoch 30/30 447/450 [============================>.] - ETA: 0s - loss: 0.4077 - accuracy: 0.8592 Epoch 30: val_accuracy did not improve from 0.86180 450/450 [==============================] - 7s 17ms/step - loss: 0.4075 - accuracy: 0.8592 - val_loss: 0.4369 - val_accuracy: 0.8532
plt.figure(1)
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='upper left')
plt.show()
Carregar o melhor modelo que obteve a melhor acurácia de validação no treinamento
model = load_model("/content/drive/My Drive/checkpoints/modelocifar.h5")
8. Cálculo da precisão de classificação no dataset de testes¶
Avaliar e imprimir a precisão do teste
score = model.evaluate(x_test, y_test, verbose=0)
print('\n', 'Test accuracy:', score[1])
Test accuracy: 0.7767000198364258
9. Visualizar algumas predições¶
As visualizações podem nos dar algumas dicas sobre por que a rede classifica erroneamente alguns objetos. Obtendo previsões no conjunto de testes:
y_hat = model.predict(x_test)
313/313 [==============================] - 1s 3ms/step
y_hat[100,:]
array([5.8770423e-05, 9.3314156e-08, 5.6933337e-03, 1.1897533e-04, 3.1580424e-01, 3.2564318e-03, 6.1175911e-08, 6.7506504e-01, 1.1326588e-06, 1.8971995e-06], dtype=float32)
np.argmax(y_hat[100,:])
7
Definindo rótulos de texto (rótulos disponíveis na fonte original: https://www.cs.toronto.edu/~kriz/cifar.html)
cifar10_labels = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
Plot de amostra aleatória de imagens de teste, rótulos preditos e a "ground truth" advinda do dataset CIFAR-10
fig = plt.figure(figsize=(20, 8))
for i, idx in enumerate(np.random.choice(x_test.shape[0], size=32, replace=False)):
ax = fig.add_subplot(4, 8, i + 1, xticks=[], yticks=[])
ax.imshow(np.squeeze(x_test[idx]))
pred_idx = np.argmax(y_hat[idx])
true_idx = np.argmax(y_test[idx])
ax.set_title("{} ({})".format(cifar10_labels[pred_idx], cifar10_labels[true_idx]),
color=("green" if pred_idx == true_idx else "red"))
# amostras corretamente classificadas em verde, incorretamente classificadas em vermelho