Um código Python para Criar e treinar um modelo de iA para Prediçao

July 5, 2025
Um código Python para Criar e treinar um modelo de iA para Prediçao

Criando um Modelo de Inteligência Artificial com PyTorch: Um Guia Detalhado

A criação de um modelo de inteligência artificial (IA) envolve uma série de etapas complexas e interconectadas. Desde a definição da arquitetura da rede neural até o ajuste fino de camadas, número de parâmetros, treinamento e testes, o processo demanda um conhecimento aprofundado, uma quantidade significativa de dados e um tempo considerável dedicado a ajustes, experimentação e validação. Este artigo tem como objetivo apresentar um modelo implementado em Python utilizando a biblioteca PyTorch, com foco em fins didáticos e na elucidação dos principais conceitos envolvidos no desenvolvimento de uma IA.

1. Definição do Modelo

A classe ModeloIA define a arquitetura da nossa rede neural. Esta rede é uma rede neural feedforward simples, composta por duas camadas lineares totalmente conectadas ( fully connected ) com uma função de ativação ReLU entre elas. A função de ativação ReLU (Rectified Linear Unit) introduz não-linearidade ao modelo, permitindo que ele aprenda relações mais complexas nos dados.

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import numpy as np

class ModeloIA(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(ModeloIA, self).__init__()
        self.linear1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        out = self.linear1(x)
        out = self.relu(out)
        out = self.linear2(out)
        return out
  • __init__: O construtor da classe define as camadas da rede neural.

    • nn.Linear(input_size, hidden_size): Cria uma camada linear que recebe um tensor de entrada com tamanho input_size e o transforma em um tensor de saída com tamanho hidden_size. Esta camada realiza uma transformação linear nos dados de entrada, aprendendo pesos e biases durante o treinamento.
    • nn.ReLU(): Aplica a função de ativação ReLU. A ReLU substitui todos os valores negativos por zero, introduzindo não-linearidade no modelo.
    • nn.Linear(hidden_size, output_size): Cria uma segunda camada linear que recebe um tensor de entrada com tamanho hidden_size e o transforma em um tensor de saída com tamanho output_size. Esta camada realiza uma transformação linear nos dados processados pela camada anterior, ajustando os pesos e biases para produzir a saída desejada.
  • forward: Define o fluxo de dados através da rede.

    • out = self.linear1(x): Aplica a primeira camada linear à entrada x.
    • out = self.relu(out): Aplica a função de ativação ReLU à saída da primeira camada linear.
    • out = self.linear2(out): Aplica a segunda camada linear à saída da função ReLU.
    • return out: Retorna a saída da rede.

2. Preparação dos Dados

A classe CustomDataset é utilizada para preparar os dados para o treinamento e teste do modelo. Ela herda da classe Dataset do PyTorch e implementa os métodos __len__ e __getitem__, que são necessários para que o DataLoader possa iterar sobre os dados.

class CustomDataset(Dataset):
    def __init__(self, X, y):
        self.X = torch.tensor(X, dtype=torch.float32)
        self.y = torch.tensor(y, dtype=torch.float32)
        self.len = len(X)

    def __len__(self):
        return self.len

    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]

# Dados de exemplo (substitua pelos seus dados reais)
X_train = np.array([[1, 2], [3, 4], [5, 6]], dtype=np.float32)
y_train = np.array([0, 1, 0], dtype=np.float32)
X_test = np.array([[7, 8], [9, 10]], dtype=np.float32)
y_test = np.array([1, 0], dtype=np.float32)

input_size = 2
hidden_size = 4
output_size = 1 # Mudado para 1 para corresponder à regressão

train_dataset = CustomDataset(X_train, y_train)
test_dataset = CustomDataset(X_test, y_test)
train_loader = DataLoader(dataset=train_dataset, batch_size=32)
test_loader = DataLoader(dataset=test_dataset, batch_size=32)
  • __init__: O construtor da classe recebe os dados de entrada X e os rótulos y e os converte em tensores do PyTorch. Ele também armazena o tamanho dos dados.

    • self.X = torch.tensor(X, dtype=torch.float32): Converte os dados de entrada X em um tensor do PyTorch com tipo de dado float32.
    • self.y = torch.tensor(y, dtype=torch.float32): Converte os rótulos y em um tensor do PyTorch com tipo de dado float32.
    • self.len = len(X): Armazena o tamanho dos dados.
  • __len__: Retorna o tamanho do dataset.

  • __getitem__: Retorna um item do dataset, dados o seu índice.

    • return self.X[idx], self.y[idx]: Retorna o item correspondente ao índice idx como um par de tensores: os dados de entrada e o rótulo.

Os dados de exemplo são criados utilizando a biblioteca NumPy. É crucial substituir esses dados pelos seus dados reais para treinar um modelo útil. Os dados são, então, encapsulados em objetos CustomDataset e carregados usando DataLoader. O DataLoader facilita o processo de iteração sobre os dados em batches (lotes), o que é essencial para o treinamento eficiente de redes neurais.

3. Instanciação do Modelo, Função de Perda e Otimizador

Nesta etapa, instanciamos o modelo ModeloIA, definimos a função de perda e o otimizador. A função de perda é utilizada para quantificar o erro entre as previsões do modelo e os rótulos reais. O otimizador é utilizado para ajustar os parâmetros do modelo de forma a minimizar a função de perda.

model = ModeloIA(input_size, hidden_size, output_size)
criterion = nn.BCEWithLogitsLoss() # Usado para classificação binária
optimizer = optim.Adam(model.parameters(), lr=0.01)
  • model = ModeloIA(input_size, hidden_size, output_size): Cria uma instância da classe ModeloIA, definindo o tamanho da entrada, o tamanho da camada escondida e o tamanho da saída.
  • criterion = nn.BCEWithLogitsLoss(): Define a função de perda como BCEWithLogitsLoss. Esta função é adequada para problemas de classificação binária, onde o objetivo é prever uma probabilidade entre 0 e 1. Ela combina uma função sigmoide com a perda de entropia cruzada binária para estabilidade numérica.
  • optimizer = optim.Adam(model.parameters(), lr=0.01): Define o otimizador como Adam. O Adam é um algoritmo de otimização popular que adapta as taxas de aprendizado para cada parâmetro. model.parameters() retorna um iterador sobre os parâmetros do modelo, e lr=0.01 define a taxa de aprendizado inicial.

4. Loop de Treinamento

O loop de treinamento itera sobre os dados de treinamento várias vezes (epochs) e ajusta os parâmetros do modelo de forma a minimizar a função de perda.

num_epochs = 100
for epoch in range(num_epochs):
    for i, (inputs, labels) in enumerate(train_loader):
        # Forward pass
        outputs = model(inputs)
        loss = criterion(outputs, labels.unsqueeze(1)) # Ajustado para corresponder à saída do modelo

        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    if (epoch+1) % 10 == 0:
        print (f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
  • num_epochs = 100: Define o número de epochs (passagens completas pelo conjunto de dados de treinamento).
  • for epoch in range(num_epochs):: Inicia o loop de treinamento.
  • for i, (inputs, labels) in enumerate(train_loader):: Itera sobre os batches de dados de treinamento.
    • inputs: Dados de entrada do batch.
    • labels: Rótulos correspondentes ao batch.
  • outputs = model(inputs): Realiza o forward pass, passando os dados de entrada pelo modelo para obter as previsões.
  • loss = criterion(outputs, labels.unsqueeze(1)): Calcula a perda entre as previsões e os rótulos reais. labels.unsqueeze(1) adiciona uma dimensão aos rótulos para que correspondam à forma da saída do modelo.
  • optimizer.zero_grad(): Zera os gradientes dos parâmetros do modelo. Isso é necessário porque o PyTorch acumula os gradientes por padrão.
  • loss.backward(): Realiza o backward pass, calculando os gradientes da perda em relação aos parâmetros do modelo.
  • optimizer.step(): Atualiza os parâmetros do modelo utilizando os gradientes calculados.
  • if (epoch+1) % 10 == 0:: Imprime a perda a cada 10 epochs.

5. Teste do Modelo

Após o treinamento, é importante testar o modelo em um conjunto de dados separado para avaliar seu desempenho e garantir que ele não esteja overfitting (memorizando os dados de treinamento).

with torch.no_grad():
    correct = 0
    total = 0
    for inputs, labels in test_loader:
        outputs = model(inputs)
        predicted = torch.round(torch.sigmoid(outputs)) # Aplica sigmoide e arredonda para classificação binária
        total += labels.size(0)
        correct += (predicted == labels.unsqueeze(1)).sum().item()

    print(f'Acurácia do modelo nos dados de teste: {100 * correct / total:.2f} %')
  • with torch.no_grad():: Desativa o cálculo de gradientes durante o teste. Isso economiza memória e aumenta a velocidade.
  • correct = 0: Inicializa o contador de previsões corretas.
  • total = 0: Inicializa o contador de exemplos totais.
  • for inputs, labels in test_loader:: Itera sobre os batches de dados de teste.
  • outputs = model(inputs): Realiza o forward pass com os dados de teste.
  • predicted = torch.round(torch.sigmoid(outputs)): Aplica a função sigmoide à saída do modelo para obter as probabilidades e, em seguida, arredonda para obter as classes previstas (0 ou 1).
  • total += labels.size(0): Atualiza o número total de exemplos.
  • correct += (predicted == labels.unsqueeze(1)).sum().item(): Compara as previsões com os rótulos reais e atualiza o número de previsões corretas.
  • print(f'Acurácia do modelo nos dados de teste: {100 * correct / total:.2f} %'): Imprime a acurácia do modelo nos dados de teste.

6. Predição com Novos Dados

Após o treinamento e teste, o modelo pode ser usado para fazer previsões em novos dados.

new_data = torch.tensor([[10, 11]], dtype=torch.float32)
with torch.no_grad():
    prediction = torch.sigmoid(model(new_data))
    print(f'Predição para novos dados: {prediction.item():.4f}')
  • new_data = torch.tensor([[10, 11]], dtype=torch.float32): Cria um tensor com os novos dados para os quais se deseja fazer uma previsão.
  • with torch.no_grad():: Desativa o cálculo de gradientes.
  • prediction = torch.sigmoid(model(new_data)): Realiza o forward pass com os novos dados e aplica a função sigmoide para obter a probabilidade prevista.
  • print(f'Predição para novos dados: {prediction.item():.4f}'): Imprime a previsão.

7. Salvando e Carregando o Modelo Treinado

É importante salvar o modelo treinado para que ele possa ser reutilizado posteriormente sem a necessidade de treinar novamente.

torch.save(model.state_dict(), 'modelo_ia.pth')
print('Modelo treinado foi salvo como modelo_ia.pth')

# Para carregar o modelo:
# model = ModeloIA(input_size, hidden_size, output_size)
# model.load_state_dict(torch.load('modelo_ia.pth'))
# model.eval()
  • torch.save(model.state_dict(), 'modelo_ia.pth'): Salva o estado do modelo (os pesos e biases aprendidos) em um arquivo chamado modelo_ia.pth.
  • model = ModeloIA(input_size, hidden_size, output_size): Cria uma nova instância do modelo.
  • model.load_state_dict(torch.load('modelo_ia.pth')): Carrega o estado do modelo salvo do arquivo modelo_ia.pth.
  • model.eval(): Coloca o modelo em modo de avaliação. Isso desativa funcionalidades como dropout e normalização em batch, que são usadas durante o treinamento, mas não durante a avaliação.