Guia Prático: Uso de torchinfo e tqdm para Inspeção de Modelos e Monitoramento de Progresso em Python

A biblioteca torchinfo oferece detalhes aprimorados sobre a arquitetura de modelos em PyTorch, como formatos de entrada/saída por camada, contagem de parâmetros e operações computacionais, superando funcionalidades semelhantes em outras ferramentas.

from torchinfo import summary
# Exemplo de uso com um modelo e tamanho de entrada definido
resumo = summary(modelo, input_size=(5, 10))

O pacote tqdm é ideal para visualizra o progresso em estruturas de iteração, sendo especialmente útil em cenários de treinamento de modelos. Sua implementação básica segue dois passos principais:

  1. Inicializar uma barra de progresso com o total de iterações, preferencialmente dentro de um bloco with para gerenciamento automático de recrusos.
  2. Atualizar a barra a cada iteração usando o método update(n).
from tqdm import tqdm
import time

# Demonstração simples de uma barra de progresso
total_passos = 8
with tqdm(total=total_passos, desc="Processando") as barra:
    for idx in range(total_passos):
        time.sleep(0.4)  # Simula operação demorada
        barra.update(1)

Parâmetros como desc e unit permitem personalizar a exibição, com unit indicando a unidade de progresso (ex.: "época", "batch", "amostra").

from tqdm import tqdm
import time

# Configuração avançada da barra de progresso
with tqdm(total=6, desc="Calculando", unidade="iteração") as barra_progresso:
    for passo in range(6):
        time.sleep(0.8)
        barra_progresso.update(1)

Uma abordagem alternativa integra diretamente o iterador, dispensando chamadas explícitas a update():

# Integração simplificada com range
for elemento in tqdm(range(4), desc="Executando tarefa", unidade="item"):
    time.sleep(0.5)

Para exibir dados em tempo real, o método set_postfix pode ser utilizado:

from tqdm import tqdm
import time

acumulador = 0
with tqdm(total=7, desc="Acumulando valores") as barra:
    for num in range(1, 8):
        time.sleep(0.25)
        acumulador += num ** 2
        barra.update(1)
        barra.set_postfix({"Soma quadrática": acumulador})

Integrando ambas as bibliotecas em um projeto de aprenddizado profundo completo:

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import time
import matplotlib.pyplot as plt
from tqdm import tqdm

# Configuração do dispositivo computacional
disp = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"Dispositivo utilizado: {disp}")

# Carregamento e preparação dos dados
digitos = load_digits()
X_dados = digitos.data
y_dados = digitos.target

X_treino, X_teste, y_treino, y_teste = train_test_split(
    X_dados, y_dados, test_size=0.25, random_state=42
)

escalador = StandardScaler()
X_treino_esc = escalador.fit_transform(X_treino)
X_teste_esc = escalador.transform(X_teste)

# Conversão para tensores PyTorch
tensor_X_treino = torch.FloatTensor(X_treino_esc).to(disp)
tensor_y_treino = torch.LongTensor(y_treino).to(disp)
tensor_X_teste = torch.FloatTensor(X_teste_esc).to(disp)
tensor_y_teste = torch.LongTensor(y_teste).to(disp)

# Definição da rede neural
class RedeNeuralSimples(nn.Module):
    def __init__(self):
        super().__init__()
        self.camada_oculta = nn.Linear(64, 32)
        self.funcao_ativacao = nn.ReLU()
        self.camada_saida = nn.Linear(32, 10)

    def forward(self, entrada):
        x = self.camada_oculta(entrada)
        x = self.funcao_ativacao(x)
        x = self.camada_saida(x)
        return x

# Inicialização do modelo e otimizador
modelo_rede = RedeNeuralSimples().to(disp)
funcao_perda = nn.CrossEntropyLoss()
otimizador = optim.Adam(modelo_rede.parameters(), lr=0.001)

# Parâmetros de treinamento
epocas_totais = 15000
historico_perda = []
epocas_marcadas = []
tempo_inicio = time.time()

# Barra de progresso durante o treinamento
with tqdm(total=epocas_totais, desc="Treinando modelo", unidade="época") as barra_treino:
    for epoca in range(epocas_totais):
        saidas = modelo_rede(tensor_X_treino)
        perda = funcao_perda(saidas, tensor_y_treino)

        otimizador.zero_grad()
        perda.backward()
        otimizador.step()

        if (epoca + 1) % 150 == 0:
            historico_perda.append(perda.item())
            epocas_marcadas.append(epoca + 1)
            barra_treino.set_postfix({"Erro atual": f"{perda.item():.4f}"})

        if (epoca + 1) % 500 == 0:
            barra_treino.update(500)

    # Garantir que a barra atinja 100%
    progresso_restante = epocas_totais - barra_treino.n
    if progresso_restante > 0:
        barra_treino.update(progresso_restante)

duracao_treino = time.time() - tempo_inicio
print(f"Duração total: {duracao_treino:.2f} segundos")

# Visualização da curva de aprendizado (opcional)
plt.figure(figsize=(9, 5))
plt.plot(epocas_marcadas, historico_perda, linestyle='--', marker='o')
plt.xlabel('Época')
plt.ylabel('Valor da Perda')
plt.title('Evolução da Função de Perda')
plt.grid(True, alpha=0.3)
plt.show()

Tags: torchinfo tqdm Pytorch Python Aprendizado Profundo

Publicado em 7-8 17:10