Classificação de personagens dos Simpsons com Redes Neurais Convolucionais (CNNs).
janeiro 13, 2025 | by rodrigo.valentim.si15@gmail.com

Redes Neurais Convolucionais (CNNs)
Redes NeuraiAs Redes Neurais Convolucionais são como um supercérebro para computadores, treinadas para entender imagens da mesma forma que “nós”. Elas ‘quebram’ as imagens em pedacinhos menores e aprendem a identificar padrões, como bordas, formas e cores. Essa habilidade as torna perfeitas para tarefas como reconhecimento facial, detecção de objetos em fotos e até mesmo condução de carros autônomos. A imagem abaixo mostra como uma CNN processa uma imagem, transformando-a em informações que o computador pode entender

Carregamento do dataset
No post de hoje, irei utilizar uma CNN para fazer a classificação de 11 personagens dos Simpsons. O primeiro passo que é carregar a nossa base de imagens, para isso, iremos utilizar a Biblioteca Keras. Além de carregar, iremos multiplicar as imagens a partir das imagens existentes, esse processo se chama Data Augmentation. O dataset contém imagens dos seguintes personagens dos Simpsons:
- ‘homer_simpson’,
- ‘krusty_the_clown’,
- ‘milhouse_van_houten’,
- ‘moe_szyslak’,
- ‘marge_simpson’,
- ‘charles_montgomery_burns’,
- ‘principal_skinner’,
- ‘lisa_simpson’,
- ‘bart_simpson’,
- ‘maggie_simpson’,
- ‘ned_flanders’
Data Augmentation
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import os
# Dfinição de o tamanho das imagens
image_size = (224, 224)
batch_size = 128
# normalização dos dados
rescale_factor = 1.0 / 255
# Aqui temos todo o processo de data augmentation nas imagens
data_datagen = ImageDataGenerator(rescale=1.0/255, validation_split=0.20, featurewise_center=False,
samplewise_center=False,
rotation_range=10, #range de rotação
zoom_range = 0.1, # range de zoom da imagem
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True,
vertical_flip=False)
#criação dos dados treino
train_ds = data_datagen.flow_from_directory( # Divido a pasta treino em (treino e validação)
"/kaggle/input/simpsons11/train/", # Path para as imagens
target_size=image_size, # all images will be resized to 224x224
batch_size=50,
class_mode='categorical',
subset='training'
)
#criação dos dados validação
val_ds = data_datagen.flow_from_directory( # Divido a pasta treino em (treino e validação)
"/kaggle/input/simpsons11/train/", # Path para as imagens
target_size=image_size, # all images will be resized to 224x224
batch_size=50,
class_mode='categorical',
subset='validation')
test_datagen = ImageDataGenerator(rescale=1.0/255)
#criação dos dados de teste
test_ds = test_datagen.flow_from_directory( # Divido a pasta treino em (treino e validação)
"/kaggle/input/simpsons11/test/", # Path para as imagens
target_size=image_size, # all images will be resized to 224x224
batch_size=50,
class_mode='categorical',
shuffle=True,
)
Veja um exemplo do Data Augmentation:

Criação do modelo
Agora vamos criar nosso modelo de visão computacional para classificar os personagens, o código abaixo utiliza a técnica de transfer-learning com o modelo VGG16, esta técnica nos possibilita utilizar um modelo já treinado em uma base diferente, esse processo otimiza nosso tempo de treinamento e, muitas vezes, facilita que nosso modelo desempenhe melhor na nossa base de dados.
from tensorflow.keras.applications import VGG16
from tensorflow.keras import regularizers
def my_model_with_vgg(input_size=(224, 224, 3), num_classes=11):
# Carrega a base da VGG16 sem as camadas densas no topo
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224,224,3))
# Congela os pesos da base para que não sejam treinados novament
model = keras.Sequential([
base_model,
layers.BatchNormalization(),
layers.Flatten(),
layers.Dense(256, activation="relu"),
layers.Dense(num_classes, activation="softmax"),
])
return model
Compilação do modelo
Agora é hora de compilar o modelo, ou seja, escolher um otimizador para o modelo e uma métrica de para ele buscar otimizar.
from keras.optimizers import SGD, RMSprop
model_vgg = my_model_with_vgg(input_size=(224, 224, 3), num_classes=11)
sgd = SGD(learning_rate=1e-3,decay=1e-6, momentum=0.9, nesterov=True)
model_vgg.summary() # Exibe a arquitetura do modelo
model_vgg.compile(loss="categorical_crossentropy", optimizer=sgd, metrics=["accuracy"])
Por fim, fazemos o treinamento do modelo e avaliamos sua performance:
Treinamento
batch_size = 128
epochs = 10
history = model_vgg.fit(train_ds, validation_data=val_ds, batch_size=batch_size, epochs=epochs)
Epoch 1/10
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1713559074.327265 94 device_compiler.h:186] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.
W0000 00:00:1713559074.350539 94 graph_launch.cc:671] Fallback to op-by-op mode because memset node breaks graph update
55/224 ━━━━━━━━━━━━━━━━━━━━ 3:35 1s/step - accuracy: 0.3075 - loss: 2.0883
W0000 00:00:1713559143.539619 94 graph_launch.cc:671] Fallback to op-by-op mode because memset node breaks graph update
224/224 ━━━━━━━━━━━━━━━━━━━━ 0s 932ms/step - accuracy: 0.6050 - loss: 1.1991
W0000 00:00:1713559285.383830 97 graph_launch.cc:671] Fallback to op-by-op mode because memset node breaks graph update
224/224 ━━━━━━━━━━━━━━━━━━━━ 402s 1s/step - accuracy: 0.6058 - loss: 1.1967 - val_accuracy: 0.8947 - val_loss: 0.3715
Epoch 2/10
W0000 00:00:1713559359.492475 95 graph_launch.cc:671] Fallback to op-by-op mode because memset node breaks graph update
224/224 ━━━━━━━━━━━━━━━━━━━━ 183s 797ms/step - accuracy: 0.9467 - loss: 0.1818 - val_accuracy: 0.9152 - val_loss: 0.2914
Epoch 3/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 182s 790ms/step - accuracy: 0.9669 - loss: 0.1229 - val_accuracy: 0.9281 - val_loss: 0.2594
Epoch 4/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 182s 793ms/step - accuracy: 0.9818 - loss: 0.0688 - val_accuracy: 0.9393 - val_loss: 0.2451
Epoch 5/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 184s 803ms/step - accuracy: 0.9879 - loss: 0.0488 - val_accuracy: 0.9055 - val_loss: 0.3884
Epoch 6/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 183s 796ms/step - accuracy: 0.9829 - loss: 0.0550 - val_accuracy: 0.9252 - val_loss: 0.3045
Epoch 7/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 182s 794ms/step - accuracy: 0.9910 - loss: 0.0356 - val_accuracy: 0.9450 - val_loss: 0.2051
Epoch 8/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 182s 794ms/step - accuracy: 0.9935 - loss: 0.0229 - val_accuracy: 0.9464 - val_loss: 0.2214
Epoch 9/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 183s 796ms/step - accuracy: 0.9954 - loss: 0.0178 - val_accuracy: 0.9418 - val_loss: 0.2477
Epoch 10/10
224/224 ━━━━━━━━━━━━━━━━━━━━ 182s 794ms/step - accuracy: 0.9978 - loss: 0.0154 - val_accuracy: 0.9306 - val_loss: 0.3211
Os resultados demonstra que nosso modelo conseguiu aprender a classificar os 11 personagens do Simpsons como se verifica na matriz de confusão:

Predições
Utilizando o modelo para fazer algumas predições em dados que ele nunca viu, verificamos que de fato o modelo aprendeu a classificar os personagens.

Para ter acesso ao código completo basta ir no meu Kaggle: https://www.kaggle.com/code/rodrigov/simpsons-character-classification