🔗 Dashboard ao vivo: https://machine-learning-upstat.streamlit.app/
Projeto de estudo de ML em séries temporais / detecção de anomalia, com foco no domínio de monitoramento de infraestrutura (CPU, rede, disco, latência, requisições) — pensado para conectar depois com o UpStat.
Vai do baseline estatístico até deep learning, sempre com avaliação correta para séries temporais (sem vazamento, com métricas pontuais e point-adjusted).
NAB — Numenta Anomaly Benchmark: séries reais
de métricas de servidor (AWS CloudWatch) e falhas de sistema com causa
conhecida, todas com janelas de anomalia rotuladas (ground truth). A
curadoria das séries está em src/config.py.
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtpython scripts/01_download.py # baixa o NAB (idempotente)
python scripts/02_eda.py # explora + plota cada série
python scripts/03_baseline.py # z-score em janela móvel (piso)
python scripts/04_isolation_forest.py # Isolation Forest sobre features
python scripts/05_lstm_autoencoder.py # LSTM Autoencoder (requer torch)
python scripts/06_compare.py # comparativo dos 3 modelos
python scripts/07_pr_curves.py # tuning de threshold + curvas PR + PR-AUC
python scripts/08_affiliation.py # métrica affiliation vs point-adjusted
python scripts/09_uptime_forecast.py # previsão de falha com antecedência (lead time)
python scripts/10_service.py # treina/persiste o detector como serviço
python -m src.service # sobe o servidor HTTP (POST /score)Os scripts 03/04/05 salvam os scores por ponto em artifacts/scores/, que os
passos 06–08 reaproveitam (sem recomputar modelos). Saídas (figuras + tabelas
em CSV) vão para artifacts/.
Interface interativa (Streamlit + Plotly) que reaproveita todo o src/:
streamlit run app.py # abre em http://localhost:8501Páginas: Visão geral (explorar séries), Detecção (resultados + métricas
por modelo), Comparação de modelos (F1/PR-AUC/affiliation), Previsão de
falha (horizonte e lead time interativos) e Serviço ao vivo (injete uma
anomalia e veja o AnomalyService pontuar em tempo real).
Para o estágio do LSTM:
pip install torch --index-url https://download.pytorch.org/whl/cpupython scripts/10_service.py # treina + persiste o modelo
python -m src.service # sobe em http://127.0.0.1:8000
curl -s -X POST http://127.0.0.1:8000/score \
-H 'Content-Type: application/json' \
-d '{"timestamps": ["2025-01-01T00:00:00", "..."], "values": [50.1, 88.7]}'
# → {"n_pontos": ..., "n_anomalias": ..., "resultados": [{timestamp, value, anomaly_score, is_anomaly}, ...]}src/
config.py caminhos + curadoria das séries NAB
data.py download, carga, rótulo binário a partir das janelas, split temporal
features.py rolling stats, diffs/lags, sazonalidade cíclica
evaluate.py F1 pontual + point-adjusted F1 (padrão AIOps)
affiliation.py affiliation-based precision/recall (Huet et al. 2021)
scoring.py persistência dos scores por ponto (reuso entre passos)
synthetic.py gerador de métrica com precursor (degradação → falha)
data_smd.py loader do SMD (multivariado, 38 métricas/máquina)
thresholding.py threshold sem rótulo: quantil e POT/EVT (GPD)
service.py AnomalyService + servidor HTTP (POST /score)
viz.py plots de série e de detecções (matplotlib, p/ artifacts)
dashboard_viz.py gráficos interativos Plotly (usados pelo dashboard)
models/
baseline.py rolling z-score + resíduo STL
iforest.py Isolation Forest sobre a matriz de features
lstm_ae.py LSTM Autoencoder (erro de reconstrução)
forecaster.py previsão de falha com horizonte (RandomForest) + lead time
multivariate.py PCA recon, IForest multi, MLP Autoencoder (SMD)
usad.py USAD — dois autoencoders adversariais (multivariado temporal)
app.py dashboard web (Streamlit) — 5 páginas interativas
scripts/ pipeline executável, um passo por arquivo (01–10)
artifacts/ figuras, scores, métricas e modelo serializado
- Split temporal, nunca aleatório. Embaralhar séries temporais vaza o
futuro no treino.
data.temporal_splitcorta no tempo. - Métrica pontual vs. point-adjusted. A pontual (acertar o ponto exato) é rígida; a point-adjusted dá a janela inteira por acerto. Veja os resultados abaixo — a escolha da métrica muda quem "vence".
- Treinar no normal (LSTM AE). O autoencoder aprende só o padrão normal (início da série) e detecta anomalia pelo erro de reconstrução alto.
Rode python scripts/06_compare.py para gerar o comparativo. Nas 9 séries:
| Modelo | F1 pontual | pa_f1 | Observação |
|---|---|---|---|
| Rolling z-score | 0.01–0.06 | 0.79–0.99 | Quase não acerta o ponto; "ganha" via janela |
| Isolation Forest | 0.11–0.49 | 0.30–0.65 | Melhor pontual em 6/9; mais falsos positivos |
| LSTM Autoencoder | 0.11–0.74 | 0.45–0.93 | Melhor em padrões complexos (regime change) |
Placar por F1 pontual: IForest 6 vitórias, LSTM AE 3.
A métrica inverte o ranking. Por F1 pontual, IForest/LSTM vencem e o baseline é quase lixo (~0.03). Por point-adjusted, o baseline "vence" quase tudo (0.99) — porque basta 1 acerto por janela para levar a janela inteira (
pa_recall=1.0). É a crítica clássica ao point-adjust; métricas como affiliation e VUS-PR são mais honestas. Lição: nunca confie numa métrica só.Destaque: LSTM AE faz F1=0.74 em
cpu_utilization_asg_misconfiguration(>2× o IForest) — mudanças graduais de regime são o forte do autoencoder.
- Tuning de threshold + PR-AUC (
07): com o threshold ótimo o baseline sobe de F1≈0.03 → 0.18–0.22, mas o PR-AUC (independe de threshold) confirma que ele é fraco de verdade (~0.10) enquanto IForest/LSTM têm sinal real (0.2–0.78). Lição: olhe sempre uma métrica threshold-independent. - Affiliation (
08): corrige o ranking enganoso do point-adjust. O baseline trivial deixa de "vencer"; LSTM/IForest dominam as séries difíceis. Em média o point-adjust superestima — não confie numa métrica só.
Reformula como classificação supervisionada: prever se haverá anomalia nas próximas H amostras (horizonte ≈ 1h). Resultado-chave:
| Cenário | precision | recall | eventos antecipados | lead time médio |
|---|---|---|---|---|
| NAB (falha abrupta) | ~0 | ~0 | quase nenhum | — |
| Sintético (com precursor) | 0.90 | 0.95 | 7/7 (100%) | 55 min |
Previsão só funciona quando há precursor (degradação gradual antes da falha). O NAB não tem → resultado negativo honesto. Falhas reais de servidor geralmente têm → é o caso do UpStat, e aí o modelo antecipa ~1h.
AnomalyService treina/persiste o detector (joblib) e expõe POST /score.
Treinado no cenário sintético, pega 100% das anomalias (recall=1.0) com alguns
falsos positivos (precision≈0.33, contamination~10%).
Caveat de produção (concept drift): treinar o IForest num regime de CPU e pontuar um período em outro nível faz ele marcar tudo como anomalia. Métricas de servidor são não-estacionárias — re-treine periodicamente ou normalize por janela móvel.
python scripts/11_smd_multivariate.py — detecção em 38 métricas correlacionadas
por máquina (Server Machine Dataset, OmniAnomaly). Detectores treinados no
tráfego normal: PCA reconstruction, Isolation Forest e MLP Autoencoder.
A anomalia aqui costuma estar na correlação entre métricas, não numa série só.
Detectores treinados no tráfego normal: PCA recon, Isolation Forest, MLP Autoencoder e USAD (dois autoencoders adversariais sobre janelas — multivariado temporal). Médias de point-adjusted F1 por forma de threshold:
| Modelo | PA-F1 quantil | PA-F1 POT | PA-F1 oracle |
|---|---|---|---|
| IForest (multi) | 0.79 | 0.73 | 0.92 |
| PCA recon | 0.47 | 0.66 | 0.91 |
| MLP Autoencoder | 0.43 | 0.44 | 0.91 |
| USAD | 0.56 | 0.37 | 0.77 |
Os "0.90 de F1" dos papers de SMD são oracle — escolhem o threshold olhando o gabarito. Com threshold honesto cai muito (crítica de Kim et al. 2022, reproduzida aqui). O POT (Peaks-Over-Threshold + GPD,
src/thresholding.py) escolhe o corte pela cauda da distribuição sem rótulo nem quantil mágico — e no PCA chega a superar o quantil fixo. Sob point-adjust um threshold agressivo infla; no F1 pontual a parcimônia do POT reduz falso alarme.
- VUS-PR: métrica threshold-independent robusta a ruído de rótulo.
- OmniAnomaly (VAE+GRU+flows): o modelo multivariado temporal mais completo.
- Integração UpStat de fato: plugar o
/scoreno fluxo de métricas real e combinar detecção (passos 04/05/11) com previsão (passo 09).