Prática
Material de Apoio¶
- Leitura complementar: cnn-pratica.md - Guia teórico sobre CNNs
Problema com MLPs Tradicionais¶
Imagine processar uma imagem 400×600 pixels com um MLP:
- Parâmetros: 400 × 600 × 100 + 100 = 24.000.100 parâmetros só na primeira camada!
- Problemas:
- Ignora estrutura espacial
- Sensível à posição
- Computacionalmente caro
- Overfitting garantido

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Flatten(input_shape=(400,600)),
layers.Dense(units=100)
])
model.summary()
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= flatten_1 (Flatten) (None, 480000) 0 dense_1 (Dense) (None, 100) 48000100 ================================================================= Total params: 48,000,100 Trainable params: 48,000,100 Non-trainable params: 0 _________________________________________________________________
Solução: Redes Neurais Convolucionais¶
A Redes Neurais Convolucionais ou CNN (Convolutional Neural Network) ou até mesmo ConvNet, são redes neurais de aprendizado profundo, Deep Learning
muito utilizadas na área de Visão Computacional classificação
,detecção de objetos
ou segmentação semântica
.
- Compartilhamento de pesos: Mesmos filtros em toda imagem
- Invariância espacial: Reconhece padrões independente da posição
- Hierarquia de features: Bordas → Formas → Objetos
- Eficiência: Drasticamente menos parâmetros
Para compreender uma CNN, precisamos compreender o funcionamento de alguns blocos novos fundamentais.
- Extração de caracteristicas
- Convolução
- Pooling
Convolução¶
A convolução permite uma filtragem no domínio espacial. Esse processo ocorre com a aplicação de filtros (pequenas matrizes), posicionadas sob cada pixel da imagem. Estes filtros, normalmente, são chamados de kernels (ou núcleos). O resultado final do valor do pixel é calculado através de um produto de convolução.
Normalmente os kernels são matrizes 3x3. E os pesos são ajustados a cada iteração pelo backpropagation
Nesta imagem temos a imagem original em azul, o kernel em cinza varrendo a imagem e o resultado da convolução em verde.

Vamos analizar o que acontece em apenas um pixel da imagem:

O resultado para cada pixel é esse:

O resultado em uma imagem é o seguinte:

Implementação em código¶
Para implementar é simples.
layers.Conv2D(filters=100, kernel_size=(3, 3), activation='relu', input_shape=(height, width, channels))
Parâmetros:
- filters: Número de filtros (kernels) - define quantos feature maps são gerados
- kernel_size: Tamanho do filtro - (3,3) é mais comum
- activation: Função de ativação aplicada após convolução
- input_shape: Formato da entrada (apenas na primeira camada)
Outros Parâmetros avançados:
- strides: Passo do filtro (default: (1,1))
- padding: 'valid' (sem padding) ou 'same' (mantém dimensão)
- dilation_rate: Convoluções dilatadas para campo receptivo maior
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
model_conv = keras.Sequential([
layers.Conv2D(
filters=100,
kernel_size=(3, 3),
activation='relu',
input_shape=(400, 600, 3),
name="conv_layer_1"
),
])
model.summary()
Model: "sequential_9" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_10 (Conv2D) (None, 798, 598, 100) 2800 ================================================================= Total params: 2,800 Trainable params: 2,800 Non-trainable params: 0 _________________________________________________________________
Desafio 1¶
Realize uma Análise de Parâmetros
comparando a quantidade de Total params
, em uma rede CNN e uma rede MLP. Em qual a quantidade de parâmetros é menor ou maior?
adote:
# Definindo dimensões de uma imagem típica
altura, largura, canais = 400, 600, 3
Para Responder:¶
- Observe os modelos criados acima
- Compare CNN (100 filtros 3×3) vs MLP (entrada flattened)
- Analise como o compartilhamento de pesos afeta o total
- Considere o que acontece com imagens maiores
Dica
# Comparação de parâmetros use: count_params()
model_params = model.count_params()
### Sua resposta aqui...
Pooling¶
De forma geral a camada de pooling
realiza uma operação de redução da imagem de entrada tentando manter as caracteristicas mais relevantes. Por consequência, o custo computacional diminui, além disso, é nesta etapa que são extraídas as característica features
mais importantes da imagem.
O pooling mais comum é utilizando um kernel 2x2, e um passo stride
de 2, por consequência a imagem de saída terá a metade da imagem de entrada. A operação de pooling irá selecionar dentro da janela do kernel o valor que será aplicado na próxima camada, pode ser o maior valor Maxpooling()
ou a média AveragePooling()

O resultado visual é o seguinte:

Implementação em código¶
Para implementar pooling é muito simples:
layers.MaxPool2D(pool_size=2, strides=2)
Parâmetros principais:
- pool_size: Tamanho da janela de pooling (2×2 é padrão)
- strides: Passo do deslocamento (geralmente = pool_size)
- padding: 'valid' (padrão) ou 'same'
Outros tipos:
layers.AveragePooling2D()
: Average poolinglayers.GlobalMaxPooling2D()
: Max pooling globallayers.GlobalAveragePooling2D()
: Average pooling global
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Conv2D(filters=100, kernel_size=(3, 3), activation='relu',
input_shape=(400, 600, 3), name="conv2d_layer"),
layers.MaxPool2D(pool_size=2, strides=2, name="maxpool_layer")
])
model.summary()
Model: "sequential_8" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_9 (Conv2D) (None, 798, 598, 100) 2800 max_pooling2d_5 (MaxPooling (None, 399, 299, 100) 0 2D) ================================================================= Total params: 2,800 Trainable params: 2,800 Non-trainable params: 0 _________________________________________________________________
Desafio 2¶
Perguntas para responder:
- Qual a dimensão da imagem antes e depois do pooling?
- A camada de pooling alterou o
total params
? - Por que o pooling não tem parâmetros treináveis?
'''
### suas respostas.....
1.
2.
'''
'\n### suas respostas.....\n\n1.\n\n\n2.\n\n\n'
Uma CNN completa é composta por duas partes principais:¶
1 Extrator de Características (Feature Extractor)¶
A extração de características é o processo pelo qual a CNN identifica padrões e características relevantes em uma imagem. As características são extraídas usando camadas convolucionais seguidas de camadas de pooling.
- Função: Detectar padrões visuais hierárquicos
- Componentes: Conv2D + Pooling + Ativação
- Processo: Bordas → Texturas → Formas → Objetos
- Saída: Feature maps com características extraídas
2 Classificador (Classifier)¶
Após a extração de características é aplicado uma rede MLP para realizar a etapa de classicação da imagem.
- Função: Tomar decisão baseada nas características
- Componentes: Flatten + Dense layers (MLP)
- Processo: Features → Combinações → Probabilidades
- Saída: Classificação final

Exemplo Prático - Fashion MNIST com CNN¶
Vamos utilizar novamente o dataset do Fashion MNIST para classificação de imagens, mas desta vez vamos utilizar uma CNN para realizar a extração de caracteristicas da imagem seguida de um classificador MLP.
Nossa Estratégia:¶
- Carregar e explorar os dados
- Pré-processar as imagens
- Construir CNN progressivamente
- Treinar e avaliar o modelo
- Visualizar resultados e interpretar erros
- Comparar com MLP tradicional
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras import layers
# Importa o dataset Fashion Mnist
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
#normaliza os dados para o pixel ficar com valores entre 0 e 1
train_images = train_images / 255.0
test_images = test_images / 255.0
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
train_images = train_images.reshape(-1,28,28,1)
print(train_images.shape)
test_images = test_images.reshape(-1,28,28,1)
test_images.shape
(60000, 28, 28, 1)
(10000, 28, 28, 1)
###### montar a arquitetura da rede neural
from tensorflow.keras import layers
model = keras.Sequential([
#####-------CNN-------####
# EXTRATOR DE CARACTERÍSTICAS#
layers.Conv2D(5, (3,3), activation='relu', padding="same", input_shape=(28, 28,1)),
layers.MaxPooling2D((2,2)),
#######------ MLP-----###
# CLASSIFICADOR #
layers.Flatten(),
layers.Dense(120, activation='relu'),
layers.Dense(10, activation='softmax') ###### neurônios especialistas
])
model.summary()
Model: "sequential_11" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_12 (Conv2D) (None, 28, 28, 5) 50 max_pooling2d_7 (MaxPooling (None, 14, 14, 5) 0 2D) flatten_5 (Flatten) (None, 980) 0 dense_9 (Dense) (None, 120) 117720 dense_10 (Dense) (None, 10) 1210 ================================================================= Total params: 118,980 Trainable params: 118,980 Non-trainable params: 0 _________________________________________________________________
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
epochs_hist = model.fit(train_images, train_labels, epochs=3, validation_split=0.2)
Epoch 1/3 1500/1500 [==============================] - 23s 15ms/step - loss: 0.2374 - accuracy: 0.9128 - val_loss: 0.2589 - val_accuracy: 0.9027 Epoch 2/3 1500/1500 [==============================] - 24s 16ms/step - loss: 0.2136 - accuracy: 0.9217 - val_loss: 0.2328 - val_accuracy: 0.9143 Epoch 3/3 1500/1500 [==============================] - 21s 14ms/step - loss: 0.1950 - accuracy: 0.9287 - val_loss: 0.2393 - val_accuracy: 0.9117
## exibe os graficos da função loss e acuracia
history_df = pd.DataFrame(epochs_hist.history)
history_df[['loss','val_loss']].plot();
history_df[['accuracy','val_accuracy']].plot();
#Validadção
train_loss, train_acc = model.evaluate(train_images, train_labels, verbose=2)
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
1875/1875 - 10s - loss: 0.1883 - accuracy: 0.9318 - 10s/epoch - 5ms/step 313/313 - 4s - loss: 0.2789 - accuracy: 0.8977 - 4s/epoch - 12ms/step
# Previsões com o modelo treinado
predictions = model.predict(test_images)
313/313 [==============================] - 2s 6ms/step
#Vericação dos itens preditos
item = 4000
print("\nClasse predita foi {} com {:2.0f}%. Classe correta é {}, {}.".format(np.argmax(predictions[item]),
100*np.max(predictions[item]),
test_labels[item],
class_names[test_labels[item]]))
a=100*np.max(predictions[item])
Classe predita foi 0 com 100%. Classe correta é 0, T-shirt/top.
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(item, predictions, test_labels, test_images)
plt.show()
Desafio 3: Implementando a LeNet-5 - A CNN Pioneira¶
O resultado não ficou muito bom, mas podemos melhorar!
A LeNet-5, desenvolvida por Yann LeCun em 1998, foi uma das primeiras CNNs bem-sucedidas e estabeleceu muitos dos princípios fundamentais ainda usados hoje.

- Convolutional Layers (CONV);
- Pooling Layers (POOL);
- Fully-Connected Layers (FC).
Um exemplo de aplicação: https://github.com/gary30404/convolutional-neural-network-from-scratch-python
Desafio para Você:¶
Implemente a LeNet-5 adaptada para Fashion MNIST (28×28) seguindo estas especificações:
###### Seu código aqui......
Batch Normalization e Dropout¶
Durante o treinamento de redes neurais profundas, é comum enfrentar problemas como instabilidade no aprendizado e overfitting. Duas técnicas utilizadas para mitigar esses problemas são:
Batch Normalization¶
A Batch Normalization (ou normalização em lote) é uma técnica que normaliza as ativações de uma camada, mantendo a média próxima de 0 e o desvio padrão próximo de 1.
Benefícios:¶
- Acelera o treinamento
- Reduz a sensibilidade à inicialização dos pesos
- Permite usar taxas de aprendizado maiores
- Atua como uma forma leve de regularização
Saiba mais em: https://machinelearningmastery.com/batch-normalization-for-training-of-deep-neural-networks/
Exemplo de uso:¶
layers.BatchNormalization()
Dropout¶
O Dropout é uma técnica de regularização que desativa aleatoriamente uma fração dos neurônios durante o treinamento. Isso força a rede a não depender de neurônios específicos, promovendo robustez e generalização. Utilize dropout principalmente em redes densas (fully connected).
Benefícios:¶
- Reduz o overfitting
- Simples de implementar
- Funciona bem em redes densas e convolucionais
Exemplo de uso:¶
layers.Dropout(0.5) # desativa 50% dos neurônios durante o treinamento
Saiba mais em: https://www.deeplearningbook.com.br/capitulo-23-como-funciona-o-dropout/
###### Seu código aqui......
### Para testar se melhora
model = keras.Sequential([
keras.Input(shape=(28, 28, 1)), # imagem de entrada
#####-------CNN-------#####
layers.Conv2D(32, (3,3), activation='relu', padding="same"),
layers.BatchNormalization(),
layers.Conv2D(64, (3,3), activation='relu', padding="same"),
layers.BatchNormalization(),
layers.MaxPooling2D((2,2)),
layers.Conv2D(128, (3,3), activation='relu', padding="same"),
layers.BatchNormalization(),
layers.MaxPooling2D((2,2)),
#######------ MLP-----####
# Flatten (transformar o mapa de características em um vetor)
layers.Flatten(),
# Camadas densas para classificação
layers.Dense(256, activation='relu'),
# layers.BatchNormalization(), # pode ajudar a estabilizar o treinamento, tem que testar!
layers.Dropout(0.5),
layers.Dense(10, activation='softmax') ###### neuroniios especialistas
])
model.summary()