Pular para o conteúdo
</>RoByte

Buscar cursos e aulas

Aulas do curso

Vídeo em breve

Por enquanto, esta aula está disponível só em texto — o vídeo entra assim que ficar pronto.

Redes neurais e projeto

Projeto final: reconhecendo dígitos manuscritos

Um projeto completo de ponta a ponta: explorar imagens, comparar modelos, avaliar erros, salvar o modelo e usá-lo em dados novos. · 25 min

Hora de juntar tudo. O projeto final é um classificador de dígitos manuscritos: dada a imagem de um número escrito à mão, o modelo diz qual dígito de 0 a 9 ela representa. É um clássico do ramo, e o mesmo fluxo serve para reconhecer objetos, placas ou gestos.

Vamos seguir o fluxo completo do projeto de ML que vimos na primeira aula.

1. Conhecendo os dados

O scikit-learn traz 1797 imagens pequenas, de 8 por 8 pixels:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits

digitos = load_digits()
X, y = digitos.data, digitos.target

print(X.shape)   # (1797, 64): cada imagem virou 64 features, uma por pixel
print(y[:10])    # os primeiros rótulos

plt.imshow(digitos.images[0], cmap="gray_r")
plt.title(f"Rótulo: {y[0]}")
plt.show()

Cada imagem 8x8 vira uma linha com 64 números, um por pixel, com o brilho de 0 a 16. Para o modelo, um dígito é só um ponto num espaço de 64 dimensões.

2. Separando treino e teste

from sklearn.model_selection import train_test_split

X_treino, X_teste, y_treino, y_teste = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)

3. Comparando modelos

Vamos treinar os três tipos de modelo que vimos, num só laço:

from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

modelos = {
    "KNN": make_pipeline(StandardScaler(), KNeighborsClassifier()),
    "Árvore": DecisionTreeClassifier(max_depth=10, random_state=42),
    "MLP": make_pipeline(
        StandardScaler(),
        MLPClassifier(hidden_layer_sizes=(64,), max_iter=500, random_state=42),
    ),
}

for nome, modelo in modelos.items():
    modelo.fit(X_treino, y_treino)
    print(f"{nome}: {modelo.score(X_teste, y_teste):.3f}")

Em geral o KNN e o MLP ficam bem acima da árvore neste problema. Os valores exatos dependem da sua versão do scikit-learn, então use os seus.

4. Avaliando de verdade

A acurácia é um bom começo, mas a matriz de confusão mostra onde o modelo erra. Vamos usar o melhor modelo:

from sklearn.metrics import confusion_matrix, classification_report

melhor = modelos["MLP"]
previsoes = melhor.predict(X_teste)

print(confusion_matrix(y_teste, previsoes))
print(classification_report(y_teste, previsoes))

Procure na matriz os pares de dígitos mais confundidos. É comum que números parecidos, como 3 e 8, ou 4 e 9, apareçam juntos nos erros.

Para ver os erros com os próprios olhos:

erros = np.where(previsoes != y_teste)[0]

for i in erros[:5]:
    plt.imshow(X_teste[i].reshape(8, 8), cmap="gray_r")
    plt.title(f"Real: {y_teste[i]} | Previsto: {previsoes[i]}")
    plt.show()

Dica

Olhar os erros costuma ensinar mais do que olhar a nota. Muitas vezes você vai olhar uma imagem errada e pensar “nem eu saberia dizer qual número é esse”, o que mostra que o modelo já está perto do limite dos dados.

5. Salvando e reutilizando o modelo

Treinar leva tempo, e usar um modelo pronto deve ser instantâneo. Com o joblib (instalado junto do scikit-learn) você salva o modelo em disco:

import joblib

joblib.dump(melhor, "digitos.joblib")

# em outro programa, ou outro dia:
modelo_carregado = joblib.load("digitos.joblib")
print(modelo_carregado.predict([X_teste[0]]))

Atenção

Como salvamos o pipeline inteiro, o StandardScaler vai junto com o modelo e é aplicado automaticamente em dados novos. Se tivesse salvado só o MLP, você teria que lembrar de padronizar os dados na mão toda vez que fosse prever.

Exercícios: evoluindo o projeto

Exercício

1. Ajuste fino. Use GridSearchCV para achar o melhor hidden_layer_sizes do MLP (teste por exemplo (32,), (64,) e (64, 32)). Ele supera o valor que usamos na aula?

Exercício

2. Matriz visual. Desenhe a matriz de confusão como um mapa de calor com ConfusionMatrixDisplay.from_predictions(y_teste, previsoes) do sklearn.metrics. Quais são os dois dígitos mais confundidos?

Exercício

3. Desafio final. Crie a imagem de um dígito seu: um array de 64 valores (entre 0 e 16) formando, por exemplo, um número 1. Passe pelo modelo com predict e veja se ele acerta. Depois tente enganá-lo desenhando um dígito ambíguo. Onde ele passa a errar?

Parabéns por chegar ao fim! Você percorreu o ciclo completo: dados, modelo, avaliação e uso. O que você aprendeu vale para problemas bem maiores. Trocar dígitos por imagens de uma câmera de robô, ou leituras de sensores por classes de terreno, é o mesmo raciocínio com dados diferentes. Os próximos passos naturais são visão computacional, redes neurais profundas e a integração de modelos com robôs.