Voltar para Labs
Frameworks

Introdução ao PyTorch na Prática: do Primeiro Neurônio à Detecção de Ataques Cibernéticos

Um guia prático que percorre os fundamentos do PyTorch — tensores, redes neurais, loops de treinamento e otimização — culminando em um projeto real de classificação de ameaças cibernéticas com o dataset BETH.

Aprender PyTorch do zero é uma jornada que combina teoria matemática, intuição sobre otimização e muita prática com código. Neste artigo, documento esse caminho — do primeiro tensor até um modelo treinado para detectar ataques cibernéticos em tráfego de rede — com os aprendizados reais e os erros que encontrei no caminho.


Por que PyTorch?

PyTorch é hoje a principal ferramenta de pesquisa e produção em Deep Learning. Sua filosofia de grafo computacional dinâmico (define-by-run) permite escrever código Python natural e depurar modelos como qualquer outro programa. Em contraste com abordagens estáticas, você vê o que acontece a cada passo — o que é essencial para aprender e experimentar.

Os principais conceitos que precisamos dominar são:

  • Tensor: a unidade básica de dado (como um ndarray do NumPy, mas com suporte a GPU e gradientes).
  • Autograd: o mecanismo de diferenciação automática que calcula gradientes para otimização.
  • nn.Module: a abstração para construir camadas e modelos.
  • Otimizador: o algoritmo que atualiza os pesos com base nos gradientes.

Parte 1: A Arquitetura de uma Rede Neural

Antes de treinar qualquer modelo, precisamos entender os três tipos de camadas fundamentais.

Camadas Lineares (Fully Connected)

Uma camada linear realiza a operação $\mathbf{y} = \mathbf{W}\mathbf{x} + \mathbf{b}$, onde $\mathbf{W}$ são os pesos aprendíveis e $\mathbf{b}$ o viés (bias). Em PyTorch:

import torch.nn as nn

layer = nn.Linear(in_features=4, out_features=2)

Funções de Ativação

Sem funções de ativação, empilhar camadas lineares é equivalente a uma única camada linear — o modelo não consegue aprender padrões não-lineares. As mais usadas são:

  • ReLU (nn.ReLU): $f(x) = \max(0, x)$ — simples e eficiente para camadas ocultas.
  • Sigmoid (nn.Sigmoid): $f(x) = \frac{1}{1 + e^{-x}}$ — comprime a saída entre 0 e 1, ideal para classificação binária.
  • Softmax: usada na saída de modelos multiclasse.

Funções de Perda (Loss)

A função de perda mede o quão errado o modelo está. A escolha depende do problema:

ProblemaSaída do ModeloLoss Correta
RegressãoValor contínuonn.MSELoss
Classificação Binária (1 neurônio + Sigmoid)Probabilidade [0,1]nn.BCELoss ou nn.BCEWithLogitsLoss
Classificação MulticlasseLogits brutosnn.CrossEntropyLoss

Armadilha comum: usar nn.CrossEntropyLoss com uma saída de 1 neurônio + Sigmoid é incorreto. Esse foi um dos erros encontrados durante o projeto e causou resultados inconsistentes.


Parte 2: O Loop de Treinamento

O coração de qualquer treinamento em PyTorch é o loop de épocas. Cada iteração segue sempre a mesma sequência de 5 passos:

for epoch in range(num_epochs):
    for xb, yb in dataloader:
        # 1. Zerar gradientes acumulados
        optimizer.zero_grad()

        # 2. Forward pass: calcular predições
        pred = model(xb)

        # 3. Calcular a perda
        loss = criterion(pred, yb)

        # 4. Backward pass: calcular gradientes
        loss.backward()

        # 5. Atualizar pesos
        optimizer.step()

Por que resetar os gradientes?

PyTorch acumula gradientes por padrão. Se você não chamar zero_grad() antes de cada batch, os gradientes da iteração anterior são somados aos atuais — corrompendo o aprendizado.

DataLoader e mini-batch

Treinar com todos os dados de uma vez (batch completo) é computacionalmente proibitivo e convergência instável para datasets grandes. O DataLoader divide o dataset em mini-batches e embaralha os dados a cada época:

from torch.utils.data import TensorDataset, DataLoader

dataset = TensorDataset(X_tensor, y_tensor)
loader = DataLoader(dataset, batch_size=256, shuffle=True)

Parte 3: Taxa de Aprendizado e Momentum

Dois hiperparâmetros que fazem enorme diferença na qualidade do treinamento.

Learning Rate (LR)

A taxa de aprendizado controla o tamanho de cada passo de atualização dos pesos. Podemos visualizar isso como uma bola descendo uma superfície de perda:

  • LR muito alto: a bola salta de um lado para o outro e pode divergir.
  • LR muito baixo: o aprendizado é lento e pode ficar preso em mínimos locais.
  • LR ideal: desce suavemente em direção ao mínimo global.

Momentum

O momentum adiciona “inércia” ao otimizador: ele mantém uma fração da direção do passo anterior, permitindo que o modelo ganhe velocidade em direções consistentes e “pule” mínimos locais rasos.

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

Em termos práticos, um momentum=0.9 é um bom ponto de partida para a maioria dos problemas.

Para a maioria dos problemas modernos, o Adam é preferível ao SGD puro, pois adapta o LR individualmente por parâmetro, combinando o efeito de momentum e escalonamento adaptativo.


Parte 4: Projeto Real — Detecção de Ataques Cibernéticos

Com os fundamentos estabelecidos, a aplicação natural é um problema do mundo real. O dataset escolhido foi o BETH (Behaviour-Expected-Through-Heuristics), que simula logs de endpoint de ambientes corporativos reais.

O Problema

Cada linha representa um evento de sistema (processo, thread, chamada de sistema). O objetivo é classificar se o evento é suspeito (sus_label=1) ou benigno (sus_label=0).

ColunaDescrição
processIdIdentificador único do processo
threadIdID da thread geradora do log
parentProcessIdProcesso pai
userIdID do usuário
mountNamespaceRestrições de namespace
argsNumNúmero de argumentos do evento
returnValueValor de retorno (geralmente 0)
sus_labelTarget: 1 = suspeito, 0 = benigno

Etapa 1: Pipeline de Dados

O pipeline de dados seguiu boas práticas essenciais para evitar data leakage:

from sklearn.preprocessing import StandardScaler

# Separar features e labels
X_train = train_df.drop('sus_label', axis=1).values
y_train = train_df['sus_label'].values

# Fit APENAS no treino
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)

# Transform nos demais com os mesmos parâmetros
X_val = scaler.transform(X_val)
X_test = scaler.transform(X_test)

Por que só fazer fit no treino?
Se calcularmos a média e desvio-padrão nos dados de validação/teste, estamos “vazando” informações futuras para o modelo. O scaler deve enxergar apenas o que o modelo enxerga em produção.

Etapa 2: Arquitetura do Modelo

Para classificação binária com BCEWithLogitsLoss (mais estável numericamente que BCELoss):

model = nn.Sequential(
    nn.Linear(input_dim, 128),
    nn.ReLU(),
    nn.Linear(128, 64),
    nn.ReLU(),
    nn.Linear(64, 1)  # Sem Sigmoid aqui — BCEWithLogitsLoss aplica internamente
)

criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)

Etapa 3: Treinamento e Resultados

Epoch 01/30 | Loss: 0.0076 | Train Acc: 0.9997 | Val Acc: 1.0000
Epoch 10/30 | Loss: 0.0022 | Train Acc: 0.9997 | Val Acc: 1.0000
Epoch 30/30 | Loss: 0.0022 | Train Acc: 0.9997 | Val Acc: 1.0000

Final Train Acc: 0.9997
Final Val Acc:   1.0000
Final Test Acc:  0.0940

A meta acadêmica foi cumprida (val_accuracy >= 0.6). Mas os números escondem algo importante.


Parte 5: A Análise que Ninguém Conta

Acurácia de 99.97% no treino e 0% no teste não é sucesso — é um sinal de alerta crítico.

A Matriz de Confusão Revela Tudo

Test confusion matrix:
 [[ 17508      0]
 [171195    264]]

Test Precision: 1.0000 | Recall: 0.0015 | F1: 0.0031

O modelo classificou 171.195 eventos maliciosos como benignos e detectou apenas 264 de 171.459. Em termos práticos:

  • Recall = 0.0015: o modelo “vê” apenas 0.15% dos ataques reais.
  • Precision = 1.0: quando alerta, não erra — mas quase nunca alerta.

Isso é o pior cenário possível para um sistema de segurança.

Por que Acurácia Engana Aqui?

O dataset tem forte desbalanceamento de classes. Se 94% dos eventos são benignos, um modelo que sempre prevê benigno atinge 94% de acurácia sem aprender nada. O modelo aprendeu esse atalho.

O que Aprendemos com este Erro

MétricaO que MedePara Segurança
Acurácia% de acertos geral❌ Enganosa em dados desbalanceados
Recall (Sensibilidade)% de ataques detectados✅ Crítico — minimiza falsos negativos
Precision% de alertas corretos✅ Importante — minimiza fadiga de alertas
F1-ScoreEquilíbrio entre Recall e Precision✅ Métrica principal para este problema
PR-AUCÁrea sob curva Precision-Recall✅ Melhor métrica global

Impacto Operacional Real

Em um Security Operations Center (SOC), esse modelo falharia catastroficamente:

  • Falso negativo (ataque não detectado): o atacante persiste no ambiente, move-se lateralmente e exfiltra dados sem bloqueio.
  • Falso positivo (benigno marcado como ataque): analistas perdem tempo investigando falsos alarmes, gerando alert fatigue e potencialmente ignorando alertas reais.

Este projeto demonstrou que em cibersegurança — especialmente com dados desbalanceados — otimizar para acurácia é o caminho errado.


Lições Aprendidas

1. Pipeline antes de modelo
Inconsistências de preprocessing (ordem de colunas, escala, encoding) destroem modelos em produção. Validar o pipeline é mais importante que tunar hiperparâmetros.

2. A função de perda define o problema
CrossEntropyLoss vs BCEWithLogitsLoss vs BCELoss não são equivalentes. Escolher errado introduz erros silenciosos que aparecem só no teste.

3. Métricas orientadas ao negócio
Acurácia é genérica. Para detecção de ameaças, o KPI real é recall da classe maliciosa. Para detecção de fraude, é F1. A métrica deve refletir o custo real de cada tipo de erro.

4. Dados desbalanceados exigem estratégia específica
Soluções para explorar: pos_weight no BCEWithLogitsLoss, oversampling (SMOTE), undersampling, ou ajuste dinâmico de limiar de decisão.

5. Validação e teste devem ser representativos
Val perfeita + teste ruim é sempre sinal de problema de dados, não de modelo.


Próximos Passos

Para transformar este experimento em um detector confiável:

  1. Corrigir o desbalanceamento com pos_weight = n_negativos / n_positivos.
  2. Buscar o limiar ótimo via curva PR na validação, não fixar em 0.5.
  3. Monitorar drift — comportamento de ataques muda com o tempo.
  4. Avaliar com PR-AUC e F1 como métricas primárias.
  5. Re-treinar periodicamente com dados rotulados atualizados.

Conclusão

A jornada de introdução ao PyTorch revelou que dominar a biblioteca é apenas o começo. O verdadeiro desafio está em entender o problema, escolher as métricas certas e garantir que o pipeline de dados seja robusto do notebook até produção.

PyTorch oferece as ferramentas. A sabedoria sobre quando e como usá-las vem da prática — e dos erros que encontramos no caminho.

“Um modelo de 99% de acurácia que deixa passar 99.85% dos ataques não é um sistema de segurança — é uma falsa sensação de proteção.”


Referências e Leituras Complementares

Documentação Oficial PyTorch

DataCamp

Dataset

  • BETH Dataset: Real Cybersecurity Data for Anomaly Detection Research — Paper e dataset originais usados neste projeto, com descrição do ambiente de coleta e estrutura dos logs.
    Highnam, K. et al. (2021). BETH Dataset: Real Cybersecurity Data for Anomaly Detection Research. ICML Workshop: Uncertainty & Robustness in Deep Learning.
    https://www.kaggle.com/datasets/katehighnam/beth-dataset

Referências Complementares

CGNjr Assistant

Celso's Portfolio

👋 Hi! I'm Celso's AI assistant. Ask me about his skills, experience, technologies, or anything related to his professional profile!

Powered by AI · Responses may be inaccurate