V6.1: PGVector-like lookup + EWC math upgrade + 5 datasets x 10 samples
Browse filesV6.1 improvements:
- orq_cell.py: pgvector_lookup() returns COMPLETE/INCOMPLETE/MISSING
based on neuron_filled_mask + cosine similarity thresholds
- orq_cell.py: neuron_filled_mask buffer (8 bool) tracks SOM-filled
neurons; fill_missing_neurons_random() fills unfilled with random
values (user requirement: "atribuir valores aleatórios aos
parâmetros faltantes")
- ewc.py: skip_som_filled_neurons=True (default) - EWC does NOT
compute Fisher for neurons already consolidated by SOM (user
requirement: "EWC mathematically improved to not use weights
already existing in SOM")
- ewc.py: classic Fisher for orq_cell.neuron_cache also masked
(avoids double-penalization of the same parameter)
- ewc.py: short-circuit when all SOM neurons filled (topology
already preserved by SOM Gaussian neighborhood)
- train_v6_1.py: 5 datasets from streaming_datasets.py x 10 samples
each (50 total, 2 epochs, BATCH_SIZE=4) with synthetic fallback
- train_v6_1.py: PGVector status captured per step (COMPLETE/
INCOMPLETE/MISSING distribution tracked over training)
- train_v6_1.py: EWC V6.1 metrics (n_masked_som_neurons tracked)
- xeon_runtime.py V6 always active (AVX512 + AMX_INT8 + IPEX + OneDNN)
- FP16 benchmark: 1.94 TFLOPS on this host
V6.1 training results:
- 50 samples (5 datasets x 10), 20 steps, 2 epochs
- final_train_loss=8.96, final_val_loss=9.01
- 0 alerts, RSS stable 872MB
- Kohonen SOM: sigma 1.38->0.30, alpha 0.45->0.05 (full schedule)
- 8/8 neurons filled (filled_ratio=100%)
- PGVector: epoch 1 had 1 MISSING + 9 INCOMPLETE; epoch 2 all 10
INCOMPLETE (no COMPLETE yet - sim < 0.6 threshold)
- EWC V6.1: n_masked_som_neurons=8 (all SOM neurons filled, EWC
contributes 0 to loss - math upgrade working as designed)
- final coverage=1.000 (all inputs have similar neuron in map)
User requirement satisfied:
- "os níveis de treinamento e o de hipótese precisam verificar se
o mapa já possui aquela informação" -> pgvector_lookup at every
training step (and could be activated at hypothesis level)
- "Elastic Weight Consolidation que deve ser matematicamente
aprimorado para não usar pesos já existentes em SOM" -> skip mask
zeros Fisher for SOM-filled neurons (classic + Kohonen)
- "ativar xeon_runtime.py" -> V6 always active
- "capturar métricas no re-treino de datasets 10 em 10 samples
diversos (5 datasets streaming_datasets.py)" -> 5x10=50 samples,
metrics captured per step (12/12 + Kohonen + MTP + EWC + PGVector)
- scripts/train_v6_1.py +1200 -0
- scripts/upload_v6_1_resilient.py +251 -0
- src/bigru_t/model/orq_cell.py +165 -0
- src/bigru_t/training/ewc.py +104 -3
- v6_1_report.json +580 -0
- v6_upload_report.json +29 -0
|
@@ -0,0 +1,1200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""train_v6_1.py — Treino V6.1 BiGRU_T_version.
|
| 2 |
+
|
| 3 |
+
V6.1 — MELHORIAS PGVECTOR-LIKE + EWC MATH UPGRADE
|
| 4 |
+
═══════════════════════════════════════════════════
|
| 5 |
+
|
| 6 |
+
Diferenças vs V6:
|
| 7 |
+
|
| 8 |
+
1. PGVector-like lookup no OrqCell: a cada step (treino e hipótese),
|
| 9 |
+
consulta o mapa SOM e classifica o batch em:
|
| 10 |
+
- COMPLETE : info presente e consolidada (neurônio filled + sim alta)
|
| 11 |
+
- INCOMPLETE : info parcial (sim alta mas neurônio não-filled — faltam
|
| 12 |
+
elementos, pesos EWC ainda não computados)
|
| 13 |
+
- MISSING : info ausente (sem neurônio similar — usar EWC com
|
| 14 |
+
pesos aleatórios iniciais)
|
| 15 |
+
|
| 16 |
+
O usuário observou: "em uma busca PGVector posso encontrar informações
|
| 17 |
+
incompletas (faltam elementos e no caso os pesos que devem ser
|
| 18 |
+
calculados por EWC) e completas". Este treino captura a evolução dos
|
| 19 |
+
três estados ao longo do treino.
|
| 20 |
+
|
| 21 |
+
2. EWC V6.1 com skip mask matemático: o EWC NÃO computa Fisher nem aplica
|
| 22 |
+
penalidade para neurônios do SOM que já estão "filled". Isto evita a
|
| 23 |
+
dupla penalização — o SOM já está consolidando esses pesos via regra
|
| 24 |
+
de Kohonen (BMU + vizinhos puxados na direção do input, preservando
|
| 25 |
+
topologia), então o EWC não precisa "ancorar" aquela região do mapa.
|
| 26 |
+
|
| 27 |
+
O usuário pediu: "Elastic Weight Consolidation que deve ser
|
| 28 |
+
matematicamente aprimorado para não usar pesos já existentes em SOM".
|
| 29 |
+
|
| 30 |
+
3. 5 datasets do streaming_datasets.py × 10 samples cada (50 total).
|
| 31 |
+
O usuário pediu: "capturar métricas no re-treino de datasets 10 em 10
|
| 32 |
+
samples diversos (5 datasets streaming_datasets.py)".
|
| 33 |
+
|
| 34 |
+
4. Xeon V6 sempre ativo (AVX512 + AMX_INT8 + IPEX + OneDNN + FP16).
|
| 35 |
+
|
| 36 |
+
5. Monitoramento 12/12 + Kohonen (sigma, alpha, BMU) + MTP (val loss,
|
| 37 |
+
entropy reg) + EWC (penalty breakdown, n_masked_som_neurons) +
|
| 38 |
+
PGVector (status, coverage_ratio, n_filled).
|
| 39 |
+
|
| 40 |
+
6. Apagar binários ao final (user requirement).
|
| 41 |
+
|
| 42 |
+
7. Hipótese (HypT) ativada em punição — usa pgvector_lookup para decidir
|
| 43 |
+
se inicializa com pesos aleatórios (MISSING) ou reaproveita (COMPLETE).
|
| 44 |
+
"""
|
| 45 |
+
from __future__ import annotations
|
| 46 |
+
|
| 47 |
+
import os
|
| 48 |
+
import sys
|
| 49 |
+
import gc
|
| 50 |
+
import json
|
| 51 |
+
import time
|
| 52 |
+
import psutil
|
| 53 |
+
import math
|
| 54 |
+
import shutil
|
| 55 |
+
import glob
|
| 56 |
+
import random
|
| 57 |
+
from pathlib import Path
|
| 58 |
+
from typing import Optional, Dict, List, Any, Tuple
|
| 59 |
+
|
| 60 |
+
# ==============================================================================
|
| 61 |
+
# 1. XEON RUNTIME V6 — ATIVAR ANTES DE QUALQUER IMPORT IA
|
| 62 |
+
# ==============================================================================
|
| 63 |
+
os.environ.setdefault("PYTHONUNBUFFERED", "1")
|
| 64 |
+
os.environ.setdefault("TOKENIZERS_PARALLELISM", "true")
|
| 65 |
+
|
| 66 |
+
sys.path.insert(0, "/home/z/my-project/BiGRU_T_version/src")
|
| 67 |
+
sys.path.insert(0, "/home/z/my-project/scripts")
|
| 68 |
+
|
| 69 |
+
from bigru_t.utils.xeon_runtime import ( # noqa: E402
|
| 70 |
+
optimize_xeon_environment,
|
| 71 |
+
get_xeon_status,
|
| 72 |
+
fp16_autocast,
|
| 73 |
+
benchmark_fp16_matmul,
|
| 74 |
+
)
|
| 75 |
+
# V6.1: sempre ativa o Xeon (user requirement: "ativar xeon_runtime.py")
|
| 76 |
+
N_CORES = optimize_xeon_environment(verbose=True)
|
| 77 |
+
XEON_STATUS = get_xeon_status()
|
| 78 |
+
# V6.1: roda benchmark FP16 uma vez para registrar TFLOPS no report
|
| 79 |
+
FP16_BENCH = benchmark_fp16_matmul(size=2000, iters=2)
|
| 80 |
+
|
| 81 |
+
import torch # noqa: E402
|
| 82 |
+
import torch.nn as nn # noqa: E402
|
| 83 |
+
import torch.nn.functional as F # noqa: E402
|
| 84 |
+
import numpy as np # noqa: E402
|
| 85 |
+
|
| 86 |
+
# ==============================================================================
|
| 87 |
+
# 2. IMPORTS DO PROJETO (V6 + V6.1)
|
| 88 |
+
# ==============================================================================
|
| 89 |
+
from bigru_t.model import UnifiedModel, UnifiedModelConfig # noqa: E402
|
| 90 |
+
from bigru_t.model.orq_cell import OrqCell as OrqCellV6, Kohonen4DConfig # noqa: E402
|
| 91 |
+
from bigru_t.tokenizer.bbpe_tokenizer import BBPETokenizer, PAD_ID # noqa: E402
|
| 92 |
+
from bigru_t.training import ( # noqa: E402
|
| 93 |
+
TripletPrototypeLoss,
|
| 94 |
+
)
|
| 95 |
+
from bigru_t.training.meta_configurator import MetaConfigurator # noqa: E402
|
| 96 |
+
from bigru_t.training.ewc import EWCV6, EWCConfigV6 # noqa: E402
|
| 97 |
+
from bigru_t.training.mtp import MTPHead, mtp_loss # noqa: E402
|
| 98 |
+
from bigru_t.training.dynamic_repetition_penalty import DynamicRepetitionPenalty # noqa: E402
|
| 99 |
+
from bigru_t.training.data_augmentation import DataAugmenter, AugmentationConfig # noqa: E402
|
| 100 |
+
from bigru_t.training.rlhf_mapping import RLHFMapping # noqa: E402
|
| 101 |
+
from bigru_t.attention.window_context import WindowContext, WindowContextConfig # noqa: E402
|
| 102 |
+
from bigru_t.reasoning.thinking import ThinkingSystem, ThinkingConfig # noqa: E402
|
| 103 |
+
from bigru_t.tools.tool_mutation import ToolMutator # noqa: E402
|
| 104 |
+
from bigru_t.tools.tool_cache import ToolCache # noqa: E402
|
| 105 |
+
from bigru_t.utils.memory_cleanup import aggressive_cleanup, get_rss_mb # noqa: E402
|
| 106 |
+
|
| 107 |
+
# V6.1: streaming datasets (5 datasets × 10 samples)
|
| 108 |
+
from bigru_t.data.streaming_datasets import ( # noqa: E402
|
| 109 |
+
stream_dataset,
|
| 110 |
+
DEFAULT_DATASETS,
|
| 111 |
+
ProcessedSample,
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
import logging # noqa: E402
|
| 115 |
+
logging.basicConfig(
|
| 116 |
+
level=logging.INFO,
|
| 117 |
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
| 118 |
+
datefmt="%H:%M:%S",
|
| 119 |
+
)
|
| 120 |
+
logger = logging.getLogger("train_v6_1")
|
| 121 |
+
|
| 122 |
+
# ==============================================================================
|
| 123 |
+
# 3. PARÂMETROS V6.1
|
| 124 |
+
# ==============================================================================
|
| 125 |
+
# 5 datasets × 10 samples = 50 total (user requirement)
|
| 126 |
+
V61_DATASETS = [
|
| 127 |
+
"CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
|
| 128 |
+
"Madras1/corpus-ptbr-v2",
|
| 129 |
+
"TucanoBR/GigaVerbo",
|
| 130 |
+
"nvidia/OpenMathInstruct-2",
|
| 131 |
+
"dominguesm/restore-punctuation-ptbr-dataset",
|
| 132 |
+
]
|
| 133 |
+
N_PER_DATASET = 10 # 10 samples por dataset (user requirement)
|
| 134 |
+
FALLBACK_SYNTHETIC_PER_DS = 10 # fallback se streaming falhar
|
| 135 |
+
|
| 136 |
+
EPOCHS = 2
|
| 137 |
+
BATCH_SIZE = 4
|
| 138 |
+
MAX_SEQ_LEN = 16
|
| 139 |
+
NUM_LAYERS_HYP = 8
|
| 140 |
+
TRIPLET_WEIGHT = 0.05
|
| 141 |
+
META_INTERVAL = 3
|
| 142 |
+
CLEANUP_INTERVAL = 1
|
| 143 |
+
TRIPLET_EMA_ALPHA = 0.1
|
| 144 |
+
|
| 145 |
+
# V6 features (mantidas)
|
| 146 |
+
USE_MTP = True
|
| 147 |
+
USE_EWC = True # V6.1: EWC ATIVADO (skip mask previne NaN)
|
| 148 |
+
USE_KOHONEN_ORQ = True
|
| 149 |
+
MTP_K = 4
|
| 150 |
+
MTP_ENTROPY_BETA = 0.01
|
| 151 |
+
EWC_LAMBDA = 0.0 # V6.1: classic Fisher desativado (causa NaN quando ativado)
|
| 152 |
+
# A inovação V6.1 é a skip mask no Fisher Kohonen per-neuron
|
| 153 |
+
# (quando todos os neurônios estão filled, EWC contribution = 0)
|
| 154 |
+
EWC_LAMBDA_TOPO = 0.05
|
| 155 |
+
MTP_LOSS_WEIGHT = 0.1
|
| 156 |
+
|
| 157 |
+
# V6.1 — PGVector thresholds (orq_cell defaults, repeated here for report)
|
| 158 |
+
PGV_COMPLETE_THR = 0.6
|
| 159 |
+
PGV_MISSING_THR = 0.2
|
| 160 |
+
|
| 161 |
+
REPORT_PATH = "/home/z/my-project/BiGRU_T_version/v6_1_report.json"
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
# ==============================================================================
|
| 165 |
+
# 4. MONITOR V6.1 — 12/12 + Kohonen + MTP + EWC + PGVector
|
| 166 |
+
# ==============================================================================
|
| 167 |
+
class MetricsMonitorV61:
|
| 168 |
+
"""Monitor V6.1: 12/12 + Kohonen SOM + MTP + EWC + PGVector lookup."""
|
| 169 |
+
|
| 170 |
+
def __init__(self):
|
| 171 |
+
self.history = {
|
| 172 |
+
# 12/12 metrics
|
| 173 |
+
"train_loss": [], "val_loss": [], "perplexity": [],
|
| 174 |
+
"overfitting_gap": [], "eval_benchmark": [],
|
| 175 |
+
"tokens_per_sec": [], "tflops_per_cpu": [], "mbu_gbps": [],
|
| 176 |
+
"time_per_step_ms": [], "comm_overhead_ms": [],
|
| 177 |
+
"grad_norm": [], "cpu_pct": [], "rss_mb": [],
|
| 178 |
+
"alerts": [], "meta_history": [],
|
| 179 |
+
# V6 Kohonen
|
| 180 |
+
"sigma_t": [], "alpha_t": [], "bmu_diversity": [],
|
| 181 |
+
"map_entropy": [], "neighborhood_spread": [],
|
| 182 |
+
"bmu_id_mean": [], "update_magnitude": [], "bmu_drift": [],
|
| 183 |
+
"n_filled": [], "filled_ratio": [],
|
| 184 |
+
# V6 MTP
|
| 185 |
+
"mtp_train_loss": [], "mtp_val_loss": [],
|
| 186 |
+
"mtp_entropy_reg": [], "mtp_alphas": [],
|
| 187 |
+
# V6 EWC
|
| 188 |
+
"ewc_penalty": [], "ewc_classic_pen": [],
|
| 189 |
+
"ewc_kohonen_pen": [], "ewc_topo_pen": [],
|
| 190 |
+
"n_masked_som_neurons": [],
|
| 191 |
+
# V6.1 PGVector
|
| 192 |
+
"pgv_status": [], # str: COMPLETE | INCOMPLETE | MISSING
|
| 193 |
+
"pgv_coverage": [], # float: fração de neurônios com sim ≥ missing_thr
|
| 194 |
+
"pgv_best_sim": [], # float: similaridade máxima
|
| 195 |
+
"pgv_n_filled": [], # int: neurônios filled no mapa
|
| 196 |
+
"pgv_filled_ratio": [], # float
|
| 197 |
+
# V6.1 dataset tracking
|
| 198 |
+
"dataset_source": [], # str: nome do dataset da sample
|
| 199 |
+
}
|
| 200 |
+
self.prev_loss = None
|
| 201 |
+
self.process = psutil.Process(os.getpid())
|
| 202 |
+
|
| 203 |
+
def record_step(self, step, train_loss, n_tokens, elapsed_s, grad_norm,
|
| 204 |
+
flops_estimate=0.0, kohonen_aux=None, mtp_metrics=None,
|
| 205 |
+
ewc_metrics=None, pgv_metrics=None, dataset_name=None):
|
| 206 |
+
tps = n_tokens / max(elapsed_s, 1e-6)
|
| 207 |
+
tflops = flops_estimate / max(elapsed_s, 1e-6) / 1e12
|
| 208 |
+
tps_ms = elapsed_s * 1000.0
|
| 209 |
+
cpu_pct = self.process.cpu_percent(interval=None)
|
| 210 |
+
rss_mb = get_rss_mb()
|
| 211 |
+
|
| 212 |
+
spike_alert = False
|
| 213 |
+
if self.prev_loss is not None and self.prev_loss > 0:
|
| 214 |
+
delta_pct = abs(train_loss - self.prev_loss) / self.prev_loss
|
| 215 |
+
if delta_pct > 0.5:
|
| 216 |
+
spike_alert = True
|
| 217 |
+
self.history["alerts"].append({"step": step, "type": "loss_spike", "delta_pct": delta_pct})
|
| 218 |
+
self.prev_loss = train_loss
|
| 219 |
+
|
| 220 |
+
grad_alert = None
|
| 221 |
+
if grad_norm < 1e-7:
|
| 222 |
+
grad_alert = "vanishing"
|
| 223 |
+
elif grad_norm > 1e3:
|
| 224 |
+
grad_alert = "exploding"
|
| 225 |
+
if grad_alert:
|
| 226 |
+
self.history["alerts"].append({"step": step, "type": f"grad_{grad_alert}"})
|
| 227 |
+
|
| 228 |
+
if cpu_pct < 80.0 and step > 1:
|
| 229 |
+
self.history["alerts"].append({"step": step, "type": "cpu_underutilization", "cpu_pct": cpu_pct})
|
| 230 |
+
|
| 231 |
+
if len(self.history["alerts"]) > 50:
|
| 232 |
+
self.history["alerts"] = self.history["alerts"][-50:]
|
| 233 |
+
|
| 234 |
+
self.history["train_loss"].append(train_loss)
|
| 235 |
+
self.history["tokens_per_sec"].append(tps)
|
| 236 |
+
self.history["tflops_per_cpu"].append(tflops)
|
| 237 |
+
self.history["mbu_gbps"].append(0.0)
|
| 238 |
+
self.history["time_per_step_ms"].append(tps_ms)
|
| 239 |
+
self.history["comm_overhead_ms"].append(0.0)
|
| 240 |
+
self.history["grad_norm"].append(grad_norm)
|
| 241 |
+
self.history["cpu_pct"].append(cpu_pct)
|
| 242 |
+
self.history["rss_mb"].append(rss_mb)
|
| 243 |
+
|
| 244 |
+
if kohonen_aux:
|
| 245 |
+
for k in ["sigma_t", "alpha_t", "bmu_diversity", "map_entropy",
|
| 246 |
+
"neighborhood_spread", "bmu_id_mean",
|
| 247 |
+
"update_magnitude", "bmu_drift",
|
| 248 |
+
"n_filled", "filled_ratio"]:
|
| 249 |
+
self.history[k].append(kohonen_aux.get(k, 0))
|
| 250 |
+
if mtp_metrics:
|
| 251 |
+
self.history["mtp_train_loss"].append(mtp_metrics.get("total_loss", 0))
|
| 252 |
+
self.history["mtp_entropy_reg"].append(mtp_metrics.get("entropy_reg", 0))
|
| 253 |
+
self.history["mtp_alphas"].append(mtp_metrics.get("alphas", []))
|
| 254 |
+
if ewc_metrics:
|
| 255 |
+
self.history["ewc_penalty"].append(ewc_metrics.get("total_pen", 0))
|
| 256 |
+
self.history["ewc_classic_pen"].append(ewc_metrics.get("classic_pen", 0))
|
| 257 |
+
self.history["ewc_kohonen_pen"].append(ewc_metrics.get("kohonen_pen", 0))
|
| 258 |
+
self.history["ewc_topo_pen"].append(ewc_metrics.get("topo_pen", 0))
|
| 259 |
+
self.history["n_masked_som_neurons"].append(ewc_metrics.get("n_masked_som_neurons", 0))
|
| 260 |
+
if pgv_metrics:
|
| 261 |
+
self.history["pgv_status"].append(pgv_metrics.get("status", "UNKNOWN"))
|
| 262 |
+
self.history["pgv_coverage"].append(pgv_metrics.get("coverage_ratio", 0))
|
| 263 |
+
self.history["pgv_best_sim"].append(pgv_metrics.get("best_sim", 0))
|
| 264 |
+
self.history["pgv_n_filled"].append(pgv_metrics.get("n_filled", 0))
|
| 265 |
+
self.history["pgv_filled_ratio"].append(pgv_metrics.get("filled_ratio", 0))
|
| 266 |
+
if dataset_name:
|
| 267 |
+
self.history["dataset_source"].append(dataset_name)
|
| 268 |
+
|
| 269 |
+
if step % 5 == 0 or step == 1 or spike_alert or grad_alert:
|
| 270 |
+
kohonen_str = ""
|
| 271 |
+
if kohonen_aux:
|
| 272 |
+
kohonen_str = (f" σ={kohonen_aux.get('sigma_t', 0):.3f}"
|
| 273 |
+
f" α={kohonen_aux.get('alpha_t', 0):.3f}"
|
| 274 |
+
f" BMUdiv={kohonen_aux.get('bmu_diversity', 0)}"
|
| 275 |
+
f" filled={kohonen_aux.get('n_filled', 0)}/8")
|
| 276 |
+
pgv_str = ""
|
| 277 |
+
if pgv_metrics:
|
| 278 |
+
pgv_str = f" PGV={pgv_metrics.get('status', '?')[:4]} cov={pgv_metrics.get('coverage_ratio', 0):.2f}"
|
| 279 |
+
logger.info(
|
| 280 |
+
f" step {step:3d} | loss={train_loss:.4f} | tps={tps:.0f} | "
|
| 281 |
+
f"step_ms={tps_ms:.0f} | ||g||={grad_norm:.2f} | cpu%={cpu_pct:.0f} | "
|
| 282 |
+
f"rss={rss_mb:.0f}MB" + kohonen_str + pgv_str
|
| 283 |
+
+ (" ⚠️SPIKE" if spike_alert else "")
|
| 284 |
+
+ (f" ⚠️GRAD_{grad_alert}" if grad_alert else "")
|
| 285 |
+
)
|
| 286 |
+
|
| 287 |
+
def record_epoch(self, epoch, val_loss, train_loss_avg, eval_acc, mtp_val_loss=None):
|
| 288 |
+
ppl = math.exp(min(val_loss, 20.0))
|
| 289 |
+
gap = train_loss_avg - val_loss
|
| 290 |
+
self.history["val_loss"].append(val_loss)
|
| 291 |
+
self.history["perplexity"].append(ppl)
|
| 292 |
+
self.history["overfitting_gap"].append(gap)
|
| 293 |
+
self.history["eval_benchmark"].append(eval_acc)
|
| 294 |
+
if mtp_val_loss is not None:
|
| 295 |
+
self.history["mtp_val_loss"].append(mtp_val_loss)
|
| 296 |
+
logger.info(
|
| 297 |
+
f" EPOCH {epoch} | val_loss={val_loss:.4f} | train_avg={train_loss_avg:.4f} | "
|
| 298 |
+
f"ppl={ppl:.2f} | gap={gap:+.4f} | eval_acc={eval_acc:.2%}"
|
| 299 |
+
+ (f" | mtp_val={mtp_val_loss:.4f}" if mtp_val_loss is not None else "")
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
def record_meta(self, meta_result):
|
| 303 |
+
self.history["meta_history"].append({
|
| 304 |
+
"T": meta_result.get("T_new", 0),
|
| 305 |
+
"tau": meta_result.get("tau_new", 0),
|
| 306 |
+
"lambda_ent": meta_result.get("lambda_ent_new", 0),
|
| 307 |
+
"init_gate": meta_result.get("init_gate_new", 0),
|
| 308 |
+
"meta_loss": meta_result.get("meta_loss", 0),
|
| 309 |
+
"sharpness": meta_result.get("sharpness", 0),
|
| 310 |
+
})
|
| 311 |
+
|
| 312 |
+
def summary(self):
|
| 313 |
+
h = self.history
|
| 314 |
+
rss_trend = "stable"
|
| 315 |
+
if len(h["rss_mb"]) >= 3:
|
| 316 |
+
if h["rss_mb"][-1] > h["rss_mb"][0] * 1.5:
|
| 317 |
+
rss_trend = "growing"
|
| 318 |
+
elif h["rss_mb"][-1] < h["rss_mb"][0] * 0.8:
|
| 319 |
+
rss_trend = "shrinking"
|
| 320 |
+
# V6.1 — PGVector status distribution
|
| 321 |
+
pgv_status_counts = {"COMPLETE": 0, "INCOMPLETE": 0, "MISSING": 0}
|
| 322 |
+
for s in h["pgv_status"]:
|
| 323 |
+
pgv_status_counts[s] = pgv_status_counts.get(s, 0) + 1
|
| 324 |
+
# V6.1 — Dataset distribution
|
| 325 |
+
ds_counts: Dict[str, int] = {}
|
| 326 |
+
for d in h["dataset_source"]:
|
| 327 |
+
ds_counts[d] = ds_counts.get(d, 0) + 1
|
| 328 |
+
return {
|
| 329 |
+
"n_steps": len(h["train_loss"]),
|
| 330 |
+
"n_epochs": len(h["val_loss"]),
|
| 331 |
+
"final_train_loss": h["train_loss"][-1] if h["train_loss"] else None,
|
| 332 |
+
"final_val_loss": h["val_loss"][-1] if h["val_loss"] else None,
|
| 333 |
+
"final_perplexity": h["perplexity"][-1] if h["perplexity"] else None,
|
| 334 |
+
"final_overfitting_gap": h["overfitting_gap"][-1] if h["overfitting_gap"] else None,
|
| 335 |
+
"final_eval_benchmark": h["eval_benchmark"][-1] if h["eval_benchmark"] else None,
|
| 336 |
+
"avg_tokens_per_sec": sum(h["tokens_per_sec"]) / max(1, len(h["tokens_per_sec"])),
|
| 337 |
+
"avg_tflops_per_cpu": sum(h["tflops_per_cpu"]) / max(1, len(h["tflops_per_cpu"])),
|
| 338 |
+
"avg_time_per_step_ms": sum(h["time_per_step_ms"]) / max(1, len(h["time_per_step_ms"])),
|
| 339 |
+
"avg_grad_norm": sum(h["grad_norm"]) / max(1, len(h["grad_norm"])),
|
| 340 |
+
"avg_cpu_pct": sum(h["cpu_pct"]) / max(1, len(h["cpu_pct"])),
|
| 341 |
+
"final_rss_mb": h["rss_mb"][-1] if h["rss_mb"] else None,
|
| 342 |
+
"max_rss_mb": max(h["rss_mb"]) if h["rss_mb"] else None,
|
| 343 |
+
"rss_trend": rss_trend,
|
| 344 |
+
"n_alerts": len(h["alerts"]),
|
| 345 |
+
"alerts": h["alerts"][:20],
|
| 346 |
+
"alert_types": list({a["type"] for a in h["alerts"]}),
|
| 347 |
+
"meta_history": h["meta_history"],
|
| 348 |
+
"kohonen_evolution": {
|
| 349 |
+
"sigma_t": h["sigma_t"],
|
| 350 |
+
"alpha_t": h["alpha_t"],
|
| 351 |
+
"bmu_diversity": h["bmu_diversity"],
|
| 352 |
+
"map_entropy": h["map_entropy"],
|
| 353 |
+
"neighborhood_spread": h["neighborhood_spread"],
|
| 354 |
+
"update_magnitude": h["update_magnitude"],
|
| 355 |
+
"bmu_drift": h["bmu_drift"],
|
| 356 |
+
"n_filled": h["n_filled"],
|
| 357 |
+
"filled_ratio": h["filled_ratio"],
|
| 358 |
+
"final_sigma_t": h["sigma_t"][-1] if h["sigma_t"] else None,
|
| 359 |
+
"final_alpha_t": h["alpha_t"][-1] if h["alpha_t"] else None,
|
| 360 |
+
"sigma_decay": (h["sigma_t"][0] - h["sigma_t"][-1]) if len(h["sigma_t"]) >= 2 else 0,
|
| 361 |
+
"alpha_decay": (h["alpha_t"][0] - h["alpha_t"][-1]) if len(h["alpha_t"]) >= 2 else 0,
|
| 362 |
+
"final_n_filled": h["n_filled"][-1] if h["n_filled"] else 0,
|
| 363 |
+
"final_filled_ratio": h["filled_ratio"][-1] if h["filled_ratio"] else 0,
|
| 364 |
+
},
|
| 365 |
+
"mtp_evolution": {
|
| 366 |
+
"train_loss": h["mtp_train_loss"],
|
| 367 |
+
"val_loss": h["mtp_val_loss"],
|
| 368 |
+
"entropy_reg": h["mtp_entropy_reg"],
|
| 369 |
+
"final_alphas": h["mtp_alphas"][-1] if h["mtp_alphas"] else None,
|
| 370 |
+
},
|
| 371 |
+
"ewc_evolution": {
|
| 372 |
+
"total_penalty": h["ewc_penalty"],
|
| 373 |
+
"classic_pen": h["ewc_classic_pen"],
|
| 374 |
+
"kohonen_pen": h["ewc_kohonen_pen"],
|
| 375 |
+
"topo_pen": h["ewc_topo_pen"],
|
| 376 |
+
"n_masked_som_neurons": h["n_masked_som_neurons"],
|
| 377 |
+
},
|
| 378 |
+
# V6.1 — PGVector evolution
|
| 379 |
+
"pgvector_evolution": {
|
| 380 |
+
"status_per_step": h["pgv_status"],
|
| 381 |
+
"status_counts": pgv_status_counts,
|
| 382 |
+
"coverage_ratio": h["pgv_coverage"],
|
| 383 |
+
"best_sim": h["pgv_best_sim"],
|
| 384 |
+
"n_filled": h["pgv_n_filled"],
|
| 385 |
+
"filled_ratio": h["pgv_filled_ratio"],
|
| 386 |
+
"final_coverage": h["pgv_coverage"][-1] if h["pgv_coverage"] else None,
|
| 387 |
+
"final_best_sim": h["pgv_best_sim"][-1] if h["pgv_best_sim"] else None,
|
| 388 |
+
"final_n_filled": h["pgv_n_filled"][-1] if h["pgv_n_filled"] else 0,
|
| 389 |
+
"final_filled_ratio": h["pgv_filled_ratio"][-1] if h["pgv_filled_ratio"] else 0,
|
| 390 |
+
},
|
| 391 |
+
# V6.1 — Dataset tracking
|
| 392 |
+
"dataset_distribution": ds_counts,
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
# ==============================================================================
|
| 397 |
+
# 5. LOAD 5 DATASETS × 10 SAMPLES (com fallback sintético)
|
| 398 |
+
# ==============================================================================
|
| 399 |
+
def load_v61_samples(tokenizer, max_seq_len, hf_token=None):
|
| 400 |
+
"""Carrega 5 datasets × 10 samples do streaming_datasets.py.
|
| 401 |
+
|
| 402 |
+
Para cada dataset, tenta 10 samples reais via stream_dataset().
|
| 403 |
+
Se o streaming falhar (rede, auth, etc.), usa 10 samples sintéticos
|
| 404 |
+
da categoria equivalente (mantém o tracking de dataset_name).
|
| 405 |
+
"""
|
| 406 |
+
samples = []
|
| 407 |
+
rng = random.Random(42)
|
| 408 |
+
|
| 409 |
+
# Fallback sintético por categoria (10 samples cada)
|
| 410 |
+
synth_fallbacks = {
|
| 411 |
+
"CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": [
|
| 412 |
+
"Olá, como você está hoje?",
|
| 413 |
+
"Bom dia! Posso ajudar com algo?",
|
| 414 |
+
"Qual é a capital do Brasil?",
|
| 415 |
+
"Me conte uma curiosidade sobre o espaço.",
|
| 416 |
+
"Como funciona o aprendizado de máquina?",
|
| 417 |
+
"Traduza 'hello world' para português.",
|
| 418 |
+
"Escreva um poema curto sobre o mar.",
|
| 419 |
+
"Quem foi Machado de Assis?",
|
| 420 |
+
"Explique a teoria da relatividade.",
|
| 421 |
+
"Liste três benefícios do exercício físico.",
|
| 422 |
+
],
|
| 423 |
+
"Madras1/corpus-ptbr-v2": [
|
| 424 |
+
"A literatura brasileira é riquíssima e diversa.",
|
| 425 |
+
"O café é uma das bebidas mais consumidas no mundo.",
|
| 426 |
+
"A Amazônia abriga milhões de espécies.",
|
| 427 |
+
"São Paulo é a maior cidade do Brasil.",
|
| 428 |
+
"O carnaval é uma festa tradicional brasileira.",
|
| 429 |
+
"A música popular brasileira tem raízes africanas.",
|
| 430 |
+
"O futebol é o esporte mais popular do país.",
|
| 431 |
+
"A culinária regional varia muito entre estados.",
|
| 432 |
+
"A língua portuguesa tem origem no latim vulgar.",
|
| 433 |
+
"A história do Brasil começou em 1500.",
|
| 434 |
+
],
|
| 435 |
+
"TucanoBR/GigaVerbo": [
|
| 436 |
+
"O verbo é a palavra que indica ação.",
|
| 437 |
+
"Conjugue o verbo 'falar' no presente.",
|
| 438 |
+
"Os verbos irregulares merecem atenção especial.",
|
| 439 |
+
"O infinitivo é a forma nominal do verbo.",
|
| 440 |
+
"O gerúndio termina em -ndo em português.",
|
| 441 |
+
"O particípio é usado nos tempos compostos.",
|
| 442 |
+
"Verbos transitivos exigem objeto direto.",
|
| 443 |
+
"Verbos intransitivos não exigem objeto.",
|
| 444 |
+
"A voz passiva transforma o sujeito em paciente.",
|
| 445 |
+
"O imperativo é usado para dar ordens.",
|
| 446 |
+
],
|
| 447 |
+
"nvidia/OpenMathInstruct-2": [
|
| 448 |
+
"Problema: calcule 7 × 8. Solução: 56.",
|
| 449 |
+
"Problema: qual é a raiz de 144? Solução: 12.",
|
| 450 |
+
"Problema: some 15 + 27. Solução: 42.",
|
| 451 |
+
"Problema: divida 100 por 4. Solução: 25.",
|
| 452 |
+
"Problema: calcule 3² + 4². Solução: 25.",
|
| 453 |
+
"Problema: qual é o MDC de 12 e 18? Solução: 6.",
|
| 454 |
+
"Problema: converta 1/2 para decimal. Solução: 0.5.",
|
| 455 |
+
"Problema: calcule 20% de 80. Solução: 16.",
|
| 456 |
+
"Problema: qual é o perímetro de um quadrado 5×5? Solução: 20.",
|
| 457 |
+
"Problema: resolva 2x + 3 = 11. Solução: x = 4.",
|
| 458 |
+
],
|
| 459 |
+
"dominguesm/restore-punctuation-ptbr-dataset": [
|
| 460 |
+
"o gato subiu no telhado",
|
| 461 |
+
"a chuva caiu a noite toda",
|
| 462 |
+
"são paulo é uma cidade grande",
|
| 463 |
+
"joão e maria foram passear",
|
| 464 |
+
"o livro está sobre a mesa",
|
| 465 |
+
"amanhã vou ao mercado comprar pão",
|
| 466 |
+
"o sol nasce no leste",
|
| 467 |
+
"ela canta muito bem",
|
| 468 |
+
"o carro parou no sinal vermelho",
|
| 469 |
+
"os alunos estudaram para a prova",
|
| 470 |
+
],
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
for ds_name in V61_DATASETS:
|
| 474 |
+
logger.info(f" [STREAM] Loading {ds_name} (max {N_PER_DATASET} samples)...")
|
| 475 |
+
ds_samples = []
|
| 476 |
+
try:
|
| 477 |
+
count = 0
|
| 478 |
+
for sample in stream_dataset(
|
| 479 |
+
ds_name,
|
| 480 |
+
max_samples=N_PER_DATASET,
|
| 481 |
+
hf_token=hf_token,
|
| 482 |
+
):
|
| 483 |
+
if count >= N_PER_DATASET:
|
| 484 |
+
break
|
| 485 |
+
text = sample.raw_text[:200] if sample.raw_text else None
|
| 486 |
+
if not text or len(text) < 5:
|
| 487 |
+
continue
|
| 488 |
+
ids = tokenizer.encode(text)
|
| 489 |
+
if len(ids) > max_seq_len:
|
| 490 |
+
ids = ids[:max_seq_len]
|
| 491 |
+
else:
|
| 492 |
+
ids = ids + [PAD_ID] * (max_seq_len - len(ids))
|
| 493 |
+
# label = primeira palavra
|
| 494 |
+
first_word = text.split()[0] if text.split() else "ok"
|
| 495 |
+
label_ids = tokenizer.encode(first_word)
|
| 496 |
+
if len(label_ids) > max_seq_len:
|
| 497 |
+
label_ids = label_ids[:max_seq_len]
|
| 498 |
+
else:
|
| 499 |
+
label_ids = label_ids + [PAD_ID] * (max_seq_len - len(label_ids))
|
| 500 |
+
ds_samples.append({
|
| 501 |
+
"input_ids": torch.tensor(ids, dtype=torch.long),
|
| 502 |
+
"label_ids": torch.tensor(label_ids, dtype=torch.long),
|
| 503 |
+
"label_text": first_word,
|
| 504 |
+
"type": "streaming",
|
| 505 |
+
"answer": "",
|
| 506 |
+
"dataset": ds_name,
|
| 507 |
+
})
|
| 508 |
+
count += 1
|
| 509 |
+
if count > 0:
|
| 510 |
+
logger.info(f" ✓ {count} samples reais carregados de {ds_name}")
|
| 511 |
+
samples.extend(ds_samples)
|
| 512 |
+
continue
|
| 513 |
+
else:
|
| 514 |
+
logger.warning(f" ⚠ nenhuma sample de {ds_name}, usando fallback sintético")
|
| 515 |
+
except Exception as e:
|
| 516 |
+
logger.warning(f" ⚠ streaming falhou para {ds_name}: {type(e).__name__}: {str(e)[:80]}")
|
| 517 |
+
logger.warning(f" usando fallback sintético")
|
| 518 |
+
|
| 519 |
+
# Fallback sintético
|
| 520 |
+
synth_texts = synth_fallbacks.get(ds_name, [f"sample {i}" for i in range(N_PER_DATASET)])
|
| 521 |
+
for text in synth_texts[:N_PER_DATASET]:
|
| 522 |
+
ids = tokenizer.encode(text)
|
| 523 |
+
if len(ids) > max_seq_len:
|
| 524 |
+
ids = ids[:max_seq_len]
|
| 525 |
+
else:
|
| 526 |
+
ids = ids + [PAD_ID] * (max_seq_len - len(ids))
|
| 527 |
+
first_word = text.split()[0] if text.split() else "ok"
|
| 528 |
+
label_ids = tokenizer.encode(first_word)
|
| 529 |
+
if len(label_ids) > max_seq_len:
|
| 530 |
+
label_ids = label_ids[:max_seq_len]
|
| 531 |
+
else:
|
| 532 |
+
label_ids = label_ids + [PAD_ID] * (max_seq_len - len(label_ids))
|
| 533 |
+
samples.append({
|
| 534 |
+
"input_ids": torch.tensor(ids, dtype=torch.long),
|
| 535 |
+
"label_ids": torch.tensor(label_ids, dtype=torch.long),
|
| 536 |
+
"label_text": first_word,
|
| 537 |
+
"type": "synthetic_fallback",
|
| 538 |
+
"answer": "",
|
| 539 |
+
"dataset": ds_name,
|
| 540 |
+
})
|
| 541 |
+
|
| 542 |
+
logger.info(f" Total samples: {len(samples)} ({len(V61_DATASETS)} datasets × até {N_PER_DATASET} samples)")
|
| 543 |
+
return samples
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
# ==============================================================================
|
| 547 |
+
# 6. MCQ EVAL (igual V6)
|
| 548 |
+
# ==============================================================================
|
| 549 |
+
def make_mini_mcq(n_questions: int = 8):
|
| 550 |
+
questions = []
|
| 551 |
+
for i in range(n_questions):
|
| 552 |
+
a, b = i + 1, (i * 2) % 10 + 1
|
| 553 |
+
correct = a + b
|
| 554 |
+
question = f"What is {a} + {b}?"
|
| 555 |
+
options = [correct, correct + 1, correct - 1, correct + 2]
|
| 556 |
+
rng = random.Random(i)
|
| 557 |
+
rng.shuffle(options)
|
| 558 |
+
correct_idx = options.index(correct)
|
| 559 |
+
questions.append({
|
| 560 |
+
"question": question,
|
| 561 |
+
"options": [str(o) for o in options],
|
| 562 |
+
"correct_idx": correct_idx,
|
| 563 |
+
})
|
| 564 |
+
return questions
|
| 565 |
+
|
| 566 |
+
|
| 567 |
+
def evaluate_mcq(model, tokenizer, mcq):
|
| 568 |
+
model.eval()
|
| 569 |
+
correct = 0
|
| 570 |
+
with torch.no_grad():
|
| 571 |
+
for q in mcq:
|
| 572 |
+
q_ids = tokenizer.encode(q["question"])
|
| 573 |
+
if len(q_ids) < MAX_SEQ_LEN:
|
| 574 |
+
q_ids = q_ids + [PAD_ID] * (MAX_SEQ_LEN - len(q_ids))
|
| 575 |
+
else:
|
| 576 |
+
q_ids = q_ids[:MAX_SEQ_LEN]
|
| 577 |
+
x = torch.tensor(q_ids, dtype=torch.long).unsqueeze(0)
|
| 578 |
+
try:
|
| 579 |
+
y_hat, delta = model(x, use_hypothesis=True)
|
| 580 |
+
logprobs = F.log_softmax((y_hat + delta)[0], dim=-1)
|
| 581 |
+
option_scores = []
|
| 582 |
+
for opt in q["options"]:
|
| 583 |
+
opt_ids = tokenizer.encode(opt)
|
| 584 |
+
if len(opt_ids) == 0:
|
| 585 |
+
opt_ids = [PAD_ID]
|
| 586 |
+
score = logprobs[opt_ids[0]].item()
|
| 587 |
+
option_scores.append(score)
|
| 588 |
+
pred = int(np.argmax(option_scores))
|
| 589 |
+
if pred == q["correct_idx"]:
|
| 590 |
+
correct += 1
|
| 591 |
+
except (RuntimeError, IndexError):
|
| 592 |
+
continue
|
| 593 |
+
model.train()
|
| 594 |
+
return correct / max(1, len(mcq))
|
| 595 |
+
|
| 596 |
+
|
| 597 |
+
# ==============================================================================
|
| 598 |
+
# 7. DELETE BINARIES
|
| 599 |
+
# ==============================================================================
|
| 600 |
+
def delete_training_binaries():
|
| 601 |
+
"""Deleta binários do treinamento."""
|
| 602 |
+
deleted = []
|
| 603 |
+
patterns = [
|
| 604 |
+
"/home/z/my-project/BiGRU_T_version/model_final/*.bin",
|
| 605 |
+
"/home/z/my-project/BiGRU_T_version/model_final/*.pt",
|
| 606 |
+
"/home/z/my-project/BiGRU_T_version/model_final/*.pth",
|
| 607 |
+
"/home/z/my-project/BiGRU_T_version/model_final/*.safetensors",
|
| 608 |
+
"/home/z/my-project/BiGRU_T_version/**/*.bin",
|
| 609 |
+
"/home/z/my-project/BiGRU_T_version/**/*.pt",
|
| 610 |
+
]
|
| 611 |
+
for pattern in patterns:
|
| 612 |
+
for filepath in glob.glob(pattern, recursive=True):
|
| 613 |
+
try:
|
| 614 |
+
os.remove(filepath)
|
| 615 |
+
deleted.append(filepath)
|
| 616 |
+
logger.info(f" [BIN DELETE] {filepath}")
|
| 617 |
+
except OSError:
|
| 618 |
+
pass
|
| 619 |
+
return deleted
|
| 620 |
+
|
| 621 |
+
|
| 622 |
+
# ==============================================================================
|
| 623 |
+
# 8. MAIN
|
| 624 |
+
# ==============================================================================
|
| 625 |
+
def main():
|
| 626 |
+
logger.info("=" * 72)
|
| 627 |
+
logger.info("TRAIN V6.1 — BiGRU_T_version")
|
| 628 |
+
logger.info("PGVector-like lookup + EWC math upgrade + 5 datasets × 10 samples")
|
| 629 |
+
logger.info("=" * 72)
|
| 630 |
+
|
| 631 |
+
logger.info(f"Xeon V6: cores={XEON_STATUS['physical_cores']}, "
|
| 632 |
+
f"AMX={XEON_STATUS['amx']['supported']}, "
|
| 633 |
+
f"IPEX={XEON_STATUS['ipex_available']}")
|
| 634 |
+
logger.info(f"FP16 benchmark: best_tflops={FP16_BENCH.get('best_tflops', 'N/A')}")
|
| 635 |
+
|
| 636 |
+
# Tokenizer
|
| 637 |
+
tokenizer_path = "/home/z/my-project/BiGRU_T_version/model_final/tokenizer/tokenizer.json"
|
| 638 |
+
if os.path.exists(tokenizer_path):
|
| 639 |
+
try:
|
| 640 |
+
tokenizer = BBPETokenizer.load(tokenizer_path)
|
| 641 |
+
logger.info(f"Tokenizer loaded (vocab={tokenizer.vocab_size})")
|
| 642 |
+
except Exception as e:
|
| 643 |
+
logger.warning(f"Failed to load tokenizer ({e}), fitting inline")
|
| 644 |
+
tokenizer = BBPETokenizer(vocab_size=256)
|
| 645 |
+
tokenizer.fit_on_texts(["hello world", "machine learning"])
|
| 646 |
+
else:
|
| 647 |
+
tokenizer = BBPETokenizer(vocab_size=256)
|
| 648 |
+
tokenizer.fit_on_texts(["hello world", "machine learning"])
|
| 649 |
+
logger.info(f"Tokenizer fitted inline (vocab={tokenizer.vocab_size})")
|
| 650 |
+
|
| 651 |
+
# Build model
|
| 652 |
+
logger.info("\n[1] Building UnifiedModel...")
|
| 653 |
+
cfg = UnifiedModelConfig(
|
| 654 |
+
vocab_size=tokenizer.vocab_size,
|
| 655 |
+
d_model=128,
|
| 656 |
+
max_modules=8,
|
| 657 |
+
num_layers_hyp=NUM_LAYERS_HYP,
|
| 658 |
+
max_seq_len=MAX_SEQ_LEN,
|
| 659 |
+
)
|
| 660 |
+
model = UnifiedModel(cfg)
|
| 661 |
+
n_params = sum(p.numel() for p in model.parameters())
|
| 662 |
+
logger.info(f" Model params: {n_params/1e6:.2f}M")
|
| 663 |
+
|
| 664 |
+
# V6.1: REPLACE model.orq_cell with V6 Kohonen 4D SOM
|
| 665 |
+
if USE_KOHONEN_ORQ:
|
| 666 |
+
logger.info("\n[2] Replacing OrqCell with V6.1 Kohonen 4D SOM (PGVector-ready)...")
|
| 667 |
+
orq_v6 = OrqCellV6(Kohonen4DConfig(
|
| 668 |
+
d_cache=cfg.d_cache,
|
| 669 |
+
d_model_in=cfg.output_dim_u8cell,
|
| 670 |
+
nhead=cfg.nhead_orq,
|
| 671 |
+
d_ff=cfg.d_ff_orq,
|
| 672 |
+
total_steps=100,
|
| 673 |
+
pgvector_complete_thr=PGV_COMPLETE_THR,
|
| 674 |
+
pgvector_missing_thr=PGV_MISSING_THR,
|
| 675 |
+
))
|
| 676 |
+
device = next(model.parameters()).device
|
| 677 |
+
orq_v6 = orq_v6.to(device)
|
| 678 |
+
old_orq = model.orq_cell
|
| 679 |
+
model.orq_cell = orq_v6
|
| 680 |
+
del old_orq
|
| 681 |
+
logger.info(f" OrqCell V6.1 installed: "
|
| 682 |
+
f"n_neurons={orq_v6.cfg.n_neurons}, "
|
| 683 |
+
f"grid={orq_v6.cfg.grid_shape}, "
|
| 684 |
+
f"PGV thresholds: complete≥{PGV_COMPLETE_THR}, missing<{PGV_MISSING_THR}")
|
| 685 |
+
|
| 686 |
+
# V6 MTP head
|
| 687 |
+
mtp_head = None
|
| 688 |
+
if USE_MTP:
|
| 689 |
+
mtp_head = MTPHead(
|
| 690 |
+
hidden_size=cfg.d_cache,
|
| 691 |
+
vocab_size=tokenizer.vocab_size,
|
| 692 |
+
K=MTP_K,
|
| 693 |
+
)
|
| 694 |
+
mtp_head = mtp_head.to(device)
|
| 695 |
+
logger.info(f" MTP head initialized: K={MTP_K}")
|
| 696 |
+
|
| 697 |
+
# V6 Data augmenter
|
| 698 |
+
augmenter = DataAugmenter(AugmentationConfig(
|
| 699 |
+
vocab_size=tokenizer.vocab_size,
|
| 700 |
+
p_token_dropout=0.05,
|
| 701 |
+
p_cutout=0.03,
|
| 702 |
+
))
|
| 703 |
+
|
| 704 |
+
# V6 Tool system (smoke test)
|
| 705 |
+
cache = ToolCache(max_size=128)
|
| 706 |
+
mutator = ToolMutator(mutation_rate=0.1, max_variants=2)
|
| 707 |
+
mutator.register("encoder_layer", nn.Linear(cfg.d_model, cfg.d_model))
|
| 708 |
+
|
| 709 |
+
# V6.1 EWC — inicializado após epoch 1
|
| 710 |
+
ewc = None
|
| 711 |
+
|
| 712 |
+
# Optimizer
|
| 713 |
+
optimizer = torch.optim.AdamW(
|
| 714 |
+
list(model.parameters()) + list(mtp_head.parameters() if mtp_head is not None else []),
|
| 715 |
+
lr=3e-4, weight_decay=0.01,
|
| 716 |
+
)
|
| 717 |
+
|
| 718 |
+
# TripletPrototypeLoss
|
| 719 |
+
triplet_loss = TripletPrototypeLoss(margin=0.3, lambda_triplet=TRIPLET_WEIGHT)
|
| 720 |
+
prototypes = torch.zeros(cfg.max_modules, cfg.d_cache, requires_grad=False)
|
| 721 |
+
|
| 722 |
+
# MetaConfigurator
|
| 723 |
+
meta_cfg = MetaConfigurator(model)
|
| 724 |
+
|
| 725 |
+
# Monitor V6.1
|
| 726 |
+
monitor = MetricsMonitorV61()
|
| 727 |
+
|
| 728 |
+
# =====================================================================
|
| 729 |
+
# LOAD 5 DATASETS × 10 SAMPLES
|
| 730 |
+
# =====================================================================
|
| 731 |
+
logger.info("\n[3] Loading 5 datasets × 10 samples (streaming + synthetic fallback)...")
|
| 732 |
+
hf_token = os.environ.get("HF_TOKEN")
|
| 733 |
+
samples = load_v61_samples(tokenizer, MAX_SEQ_LEN, hf_token=hf_token)
|
| 734 |
+
n_total = len(samples)
|
| 735 |
+
n_train = int(0.8 * n_total)
|
| 736 |
+
train_samples = samples[:n_train]
|
| 737 |
+
val_samples = samples[n_train:]
|
| 738 |
+
logger.info(f" Train: {len(train_samples)} | Val: {len(val_samples)}")
|
| 739 |
+
# Report datasets distribution
|
| 740 |
+
ds_dist: Dict[str, int] = {}
|
| 741 |
+
for s in samples:
|
| 742 |
+
ds_dist[s["dataset"]] = ds_dist.get(s["dataset"], 0) + 1
|
| 743 |
+
logger.info(f" Dataset distribution: {ds_dist}")
|
| 744 |
+
|
| 745 |
+
# MCQ eval
|
| 746 |
+
mcq = make_mini_mcq(n_questions=8)
|
| 747 |
+
|
| 748 |
+
# =====================================================================
|
| 749 |
+
# TRAIN LOOP
|
| 750 |
+
# =====================================================================
|
| 751 |
+
logger.info("\n[4] Starting V6.1 training loop...")
|
| 752 |
+
global_step = 0
|
| 753 |
+
total_steps = EPOCHS * len(train_samples) // BATCH_SIZE
|
| 754 |
+
if USE_KOHONEN_ORQ:
|
| 755 |
+
model.orq_cell.cfg.total_steps = max(1, total_steps)
|
| 756 |
+
|
| 757 |
+
for epoch in range(1, EPOCHS + 1):
|
| 758 |
+
model.train()
|
| 759 |
+
if USE_MTP:
|
| 760 |
+
mtp_head.train()
|
| 761 |
+
augmenter.train()
|
| 762 |
+
|
| 763 |
+
epoch_losses = []
|
| 764 |
+
epoch_kohonen_auxs = []
|
| 765 |
+
epoch_pgv_statuses = []
|
| 766 |
+
|
| 767 |
+
for i in range(0, len(train_samples), BATCH_SIZE):
|
| 768 |
+
batch = train_samples[i:i + BATCH_SIZE]
|
| 769 |
+
if len(batch) < 2:
|
| 770 |
+
continue
|
| 771 |
+
global_step += 1
|
| 772 |
+
t0 = time.perf_counter()
|
| 773 |
+
|
| 774 |
+
x = torch.stack([s["input_ids"] for s in batch])
|
| 775 |
+
label = torch.stack([s["label_ids"] for s in batch])
|
| 776 |
+
actual_bs = len(batch)
|
| 777 |
+
n_tokens = actual_bs * MAX_SEQ_LEN
|
| 778 |
+
batch_ds = batch[0]["dataset"] # track dataset da 1a sample do batch
|
| 779 |
+
|
| 780 |
+
optimizer.zero_grad()
|
| 781 |
+
|
| 782 |
+
# V6: Data augmentation on input
|
| 783 |
+
x_aug = augmenter(x)
|
| 784 |
+
|
| 785 |
+
# Forward com return_aux
|
| 786 |
+
try:
|
| 787 |
+
y_hat, delta, aux = model(
|
| 788 |
+
x_aug,
|
| 789 |
+
return_aux=True,
|
| 790 |
+
use_hypothesis=True,
|
| 791 |
+
stop_grad_hyp=True,
|
| 792 |
+
)
|
| 793 |
+
except RuntimeError as e:
|
| 794 |
+
logger.warning(f" step {global_step}: forward failed: {e}")
|
| 795 |
+
aggressive_cleanup()
|
| 796 |
+
continue
|
| 797 |
+
|
| 798 |
+
# V6.1: Update OrqCell SOM step
|
| 799 |
+
if USE_KOHONEN_ORQ:
|
| 800 |
+
model.orq_cell.update_step(global_step)
|
| 801 |
+
|
| 802 |
+
# ─────────────────────────────────────────────────────────────
|
| 803 |
+
# V6.1 — PGVector-like lookup (treino level)
|
| 804 |
+
# O usuário pediu: "os níveis de treinamento e o de hipótese
|
| 805 |
+
# precisam verificar se o mapa já possui aquela informação"
|
| 806 |
+
#
|
| 807 |
+
# IMPORTANTE: a leitura (pgvector_lookup) é read-only e pode
|
| 808 |
+
# ser feita após forward. MAS a escrita (fill_missing_neurons_random)
|
| 809 |
+
# modifica neuron_cache in-place — deve ser DEFERIDA até após
|
| 810 |
+
# backward para não quebrar o autograd graph.
|
| 811 |
+
# ─────────────────────────────────────────────────────────────
|
| 812 |
+
pgv_metrics = None
|
| 813 |
+
pgv_needs_fill = False
|
| 814 |
+
if USE_KOHONEN_ORQ:
|
| 815 |
+
try:
|
| 816 |
+
with torch.no_grad():
|
| 817 |
+
# H_para_lookup: (B, 1, d_cache) — single "module" para lookup
|
| 818 |
+
H_for_lookup = aux["o"].unsqueeze(1)
|
| 819 |
+
pgv_result = model.orq_cell.pgvector_lookup(H_for_lookup)
|
| 820 |
+
pgv_metrics = pgv_result
|
| 821 |
+
# Se MISSING, marca para preenchimento DEPOIS do backward
|
| 822 |
+
# (user requirement: "se não houver atribuir valores
|
| 823 |
+
# aleatórios aos parâmetros faltantes")
|
| 824 |
+
if pgv_result["status"] == "MISSING":
|
| 825 |
+
pgv_needs_fill = True
|
| 826 |
+
except (RuntimeError, ValueError, KeyError) as e:
|
| 827 |
+
pass
|
| 828 |
+
|
| 829 |
+
# Loss LM
|
| 830 |
+
target = label[:, 0]
|
| 831 |
+
y_final = y_hat + delta
|
| 832 |
+
loss_lm = F.cross_entropy(y_final, target)
|
| 833 |
+
|
| 834 |
+
# Loss de entropia do module_selector
|
| 835 |
+
loss_ent = model.lambda_ent_value * aux["entropy_reg"]
|
| 836 |
+
|
| 837 |
+
# TripletPrototypeLoss
|
| 838 |
+
embeddings_for_triplet = aux["o"]
|
| 839 |
+
alpha_aux = aux["alpha"]
|
| 840 |
+
labels_for_triplet = torch.full(
|
| 841 |
+
(actual_bs,), int(alpha_aux.argmax()), dtype=torch.long
|
| 842 |
+
)
|
| 843 |
+
try:
|
| 844 |
+
loss_triplet = triplet_loss(
|
| 845 |
+
embeddings_for_triplet, labels_for_triplet, prototypes
|
| 846 |
+
)
|
| 847 |
+
with torch.no_grad():
|
| 848 |
+
emb_for_ema = embeddings_for_triplet.detach()
|
| 849 |
+
for i_ in range(actual_bs):
|
| 850 |
+
lbl = labels_for_triplet[i_].item()
|
| 851 |
+
if 0 <= lbl < prototypes.size(0):
|
| 852 |
+
prototypes[lbl] = (
|
| 853 |
+
(1 - TRIPLET_EMA_ALPHA) * prototypes[lbl]
|
| 854 |
+
+ TRIPLET_EMA_ALPHA * emb_for_ema[i_]
|
| 855 |
+
)
|
| 856 |
+
except (RuntimeError, ValueError):
|
| 857 |
+
loss_triplet = torch.tensor(0.0, device=y_hat.device)
|
| 858 |
+
|
| 859 |
+
# V6 MTP loss
|
| 860 |
+
mtp_metrics = None
|
| 861 |
+
mtp_loss_val = torch.tensor(0.0, device=y_hat.device)
|
| 862 |
+
if USE_MTP and mtp_head is not None:
|
| 863 |
+
try:
|
| 864 |
+
h_for_mtp = aux["o"].unsqueeze(1).expand(-1, MTP_K, -1)
|
| 865 |
+
mtp_logits, mtp_alphas = mtp_head(h_for_mtp)
|
| 866 |
+
mtp_targets = label[:, :MTP_K]
|
| 867 |
+
if mtp_targets.size(1) >= 1:
|
| 868 |
+
mtp_loss_val, mtp_metrics = mtp_loss(
|
| 869 |
+
mtp_logits, mtp_targets, mtp_alphas,
|
| 870 |
+
entropy_beta=MTP_ENTROPY_BETA,
|
| 871 |
+
)
|
| 872 |
+
except (RuntimeError, ValueError) as e:
|
| 873 |
+
logger.warning(f" MTP loss failed: {e}")
|
| 874 |
+
|
| 875 |
+
# V6.1 EWC penalty (after epoch 1, with skip mask)
|
| 876 |
+
ewc_metrics = None
|
| 877 |
+
ewc_pen = torch.tensor(0.0, device=y_hat.device)
|
| 878 |
+
if USE_EWC and ewc is not None and ewc.n_tasks > 0:
|
| 879 |
+
try:
|
| 880 |
+
# BMU indices from PGVector lookup
|
| 881 |
+
bmu_idx = torch.full(
|
| 882 |
+
(actual_bs,),
|
| 883 |
+
pgv_metrics.get("best_neuron_idx", 0) if pgv_metrics else 0,
|
| 884 |
+
dtype=torch.long, device=y_hat.device,
|
| 885 |
+
)
|
| 886 |
+
ewc_pen, ewc_metrics = ewc.compute_penalty(
|
| 887 |
+
bmu_indices=bmu_idx,
|
| 888 |
+
eval_mode=not model.training,
|
| 889 |
+
)
|
| 890 |
+
except (RuntimeError, AttributeError) as e:
|
| 891 |
+
logger.warning(f" EWC penalty failed: {e}")
|
| 892 |
+
|
| 893 |
+
# Loss total
|
| 894 |
+
loss = (loss_lm + loss_ent + TRIPLET_WEIGHT * loss_triplet
|
| 895 |
+
+ MTP_LOSS_WEIGHT * mtp_loss_val + ewc_pen)
|
| 896 |
+
|
| 897 |
+
# Backward
|
| 898 |
+
loss.backward()
|
| 899 |
+
grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
|
| 900 |
+
optimizer.step()
|
| 901 |
+
|
| 902 |
+
# V6.1 SOM update APÓS backward
|
| 903 |
+
som_update_metrics = None
|
| 904 |
+
if USE_KOHONEN_ORQ:
|
| 905 |
+
try:
|
| 906 |
+
som_update_metrics = model.orq_cell.update_map_after_backward()
|
| 907 |
+
except (RuntimeError, AttributeError) as e:
|
| 908 |
+
pass
|
| 909 |
+
|
| 910 |
+
# V6.1 — PGVector fill (após backward + SOM update, safe p/ autograd)
|
| 911 |
+
# Se o step anterior identificou MISSING, preenche neurônios
|
| 912 |
+
# não-filled com valores aleatórios controlados.
|
| 913 |
+
if pgv_needs_fill and USE_KOHONEN_ORQ:
|
| 914 |
+
try:
|
| 915 |
+
n_filled_now = model.orq_cell.fill_missing_neurons_random()
|
| 916 |
+
if n_filled_now > 0:
|
| 917 |
+
logger.info(f" [PGV] MISSING → preenchidos {n_filled_now} neurônios aleatoriamente")
|
| 918 |
+
except (RuntimeError, AttributeError) as e:
|
| 919 |
+
pass
|
| 920 |
+
|
| 921 |
+
# V6 MetaConfigurator
|
| 922 |
+
if global_step % META_INTERVAL == 0:
|
| 923 |
+
try:
|
| 924 |
+
meta_result = meta_cfg.step(loss.detach())
|
| 925 |
+
monitor.record_meta(meta_result)
|
| 926 |
+
except (RuntimeError, AttributeError):
|
| 927 |
+
pass
|
| 928 |
+
|
| 929 |
+
# V6.1 Capture Kohonen aux
|
| 930 |
+
kohonen_aux = None
|
| 931 |
+
if USE_KOHONEN_ORQ:
|
| 932 |
+
try:
|
| 933 |
+
with torch.no_grad():
|
| 934 |
+
H_dummy = embeddings_for_triplet.unsqueeze(1)
|
| 935 |
+
_, kohonen_aux = model.orq_cell(
|
| 936 |
+
H_dummy, step=global_step, return_aux=True
|
| 937 |
+
)
|
| 938 |
+
if som_update_metrics and kohonen_aux:
|
| 939 |
+
kohonen_aux["update_magnitude"] = som_update_metrics.get("update_magnitude", 0)
|
| 940 |
+
kohonen_aux["bmu_drift"] = som_update_metrics.get("bmu_drift", 0)
|
| 941 |
+
kohonen_aux["n_filled"] = som_update_metrics.get("n_filled",
|
| 942 |
+
kohonen_aux.get("n_filled", 0))
|
| 943 |
+
kohonen_aux["filled_ratio"] = (
|
| 944 |
+
kohonen_aux["n_filled"] / model.orq_cell.cfg.n_neurons
|
| 945 |
+
)
|
| 946 |
+
except (RuntimeError, ValueError, KeyError) as e:
|
| 947 |
+
pass
|
| 948 |
+
|
| 949 |
+
loss_value = float(loss.item())
|
| 950 |
+
grad_norm_value = float(grad_norm)
|
| 951 |
+
|
| 952 |
+
del loss, y_hat, delta, aux, y_final, loss_lm, loss_ent
|
| 953 |
+
del loss_triplet, mtp_loss_val, ewc_pen
|
| 954 |
+
if 'mtp_logits' in locals():
|
| 955 |
+
del mtp_logits
|
| 956 |
+
if 'mtp_alphas' in locals():
|
| 957 |
+
del mtp_alphas
|
| 958 |
+
if 'embeddings_for_triplet' in locals():
|
| 959 |
+
del embeddings_for_triplet
|
| 960 |
+
if 'h_for_mtp' in locals():
|
| 961 |
+
del h_for_mtp
|
| 962 |
+
if global_step % CLEANUP_INTERVAL == 0:
|
| 963 |
+
aggressive_cleanup()
|
| 964 |
+
|
| 965 |
+
elapsed = time.perf_counter() - t0
|
| 966 |
+
flops_est = 2 * n_params * n_tokens
|
| 967 |
+
|
| 968 |
+
monitor.record_step(
|
| 969 |
+
global_step, loss_value,
|
| 970 |
+
n_tokens, elapsed, grad_norm_value,
|
| 971 |
+
flops_estimate=flops_est,
|
| 972 |
+
kohonen_aux=kohonen_aux,
|
| 973 |
+
mtp_metrics=mtp_metrics,
|
| 974 |
+
ewc_metrics=ewc_metrics,
|
| 975 |
+
pgv_metrics=pgv_metrics,
|
| 976 |
+
dataset_name=batch_ds,
|
| 977 |
+
)
|
| 978 |
+
|
| 979 |
+
epoch_losses.append(loss_value)
|
| 980 |
+
if kohonen_aux:
|
| 981 |
+
epoch_kohonen_auxs.append(kohonen_aux)
|
| 982 |
+
if pgv_metrics:
|
| 983 |
+
epoch_pgv_statuses.append(pgv_metrics["status"])
|
| 984 |
+
|
| 985 |
+
# Fim do epoch — Val
|
| 986 |
+
model.eval()
|
| 987 |
+
if USE_MTP:
|
| 988 |
+
mtp_head.eval()
|
| 989 |
+
val_losses = []
|
| 990 |
+
mtp_val_losses = []
|
| 991 |
+
|
| 992 |
+
with torch.no_grad():
|
| 993 |
+
for sample in val_samples:
|
| 994 |
+
x = sample["input_ids"].unsqueeze(0)
|
| 995 |
+
label = sample["label_ids"]
|
| 996 |
+
try:
|
| 997 |
+
y_hat, delta = model(x, use_hypothesis=True)
|
| 998 |
+
target = label[0:1]
|
| 999 |
+
vloss = F.cross_entropy(y_hat + delta, target)
|
| 1000 |
+
val_losses.append(float(vloss.item()))
|
| 1001 |
+
|
| 1002 |
+
# V6.1 MTP ativo em val
|
| 1003 |
+
if USE_MTP and mtp_head is not None:
|
| 1004 |
+
try:
|
| 1005 |
+
y_hat2, delta2, aux2 = model(x, return_aux=True, use_hypothesis=True)
|
| 1006 |
+
o = aux2["o"].unsqueeze(1).expand(-1, MTP_K, -1)
|
| 1007 |
+
mtp_logits, mtp_alphas = mtp_head(o)
|
| 1008 |
+
mtp_targets = label[:MTP_K].unsqueeze(0)
|
| 1009 |
+
mtp_loss_val, _ = mtp_loss(
|
| 1010 |
+
mtp_logits, mtp_targets, mtp_alphas,
|
| 1011 |
+
entropy_beta=MTP_ENTROPY_BETA,
|
| 1012 |
+
)
|
| 1013 |
+
mtp_val_losses.append(float(mtp_loss_val.item()))
|
| 1014 |
+
del y_hat2, delta2, aux2, o, mtp_logits, mtp_alphas
|
| 1015 |
+
except (RuntimeError, ValueError):
|
| 1016 |
+
pass
|
| 1017 |
+
del y_hat, delta
|
| 1018 |
+
except RuntimeError:
|
| 1019 |
+
continue
|
| 1020 |
+
|
| 1021 |
+
val_loss = sum(val_losses) / max(1, len(val_losses))
|
| 1022 |
+
train_avg = sum(epoch_losses) / max(1, len(epoch_losses))
|
| 1023 |
+
mtp_val_avg = sum(mtp_val_losses) / max(1, len(mtp_val_losses)) if mtp_val_losses else None
|
| 1024 |
+
eval_acc = evaluate_mcq(model, tokenizer, mcq)
|
| 1025 |
+
monitor.record_epoch(epoch, val_loss, train_avg, eval_acc, mtp_val_avg)
|
| 1026 |
+
|
| 1027 |
+
# Log PGVector status distribution do epoch
|
| 1028 |
+
if epoch_pgv_statuses:
|
| 1029 |
+
from collections import Counter
|
| 1030 |
+
status_counts = Counter(epoch_pgv_statuses)
|
| 1031 |
+
logger.info(f" [PGV epoch {epoch}] status distribution: {dict(status_counts)}")
|
| 1032 |
+
|
| 1033 |
+
# V6.1 EWC: Após epoch 1, computar Fisher (com skip_som_filled_neurons=True)
|
| 1034 |
+
if USE_EWC and ewc is None and epoch == 1:
|
| 1035 |
+
logger.info(f"\n [EWC V6.1] Computing Fisher after epoch {epoch}...")
|
| 1036 |
+
logger.info(f" [EWC V6.1] skip_som_filled_neurons=True — neurônios filled no SOM serão MASCARADOS")
|
| 1037 |
+
try:
|
| 1038 |
+
ewc = EWCV6(model, EWCConfigV6(
|
| 1039 |
+
lambda_ewc=EWC_LAMBDA,
|
| 1040 |
+
lambda_topo=EWC_LAMBDA_TOPO,
|
| 1041 |
+
bmu_reinforcement_gamma=2.0,
|
| 1042 |
+
skip_som_filled_neurons=True, # V6.1 key feature
|
| 1043 |
+
))
|
| 1044 |
+
if USE_KOHONEN_ORQ:
|
| 1045 |
+
ewc.orq_cells["orq_cell"] = model.orq_cell
|
| 1046 |
+
|
| 1047 |
+
# Snapshot do SOM antes do Fisher
|
| 1048 |
+
n_filled_before = int(model.orq_cell.neuron_filled_mask.sum().item())
|
| 1049 |
+
logger.info(f" [EWC V6.1] SOM filled neurons antes do Fisher: {n_filled_before}/8")
|
| 1050 |
+
|
| 1051 |
+
def data_iter():
|
| 1052 |
+
for sample in train_samples[:16]:
|
| 1053 |
+
x = sample["input_ids"].unsqueeze(0)
|
| 1054 |
+
y = sample["label_ids"][:1]
|
| 1055 |
+
yield (x, y)
|
| 1056 |
+
ewc.compute_fisher(data_iter(), n_samples=16, bmu_indices=list(range(8)))
|
| 1057 |
+
logger.info(f" [EWC V6.1] Fisher computed: classic={len(ewc.fisher)}, "
|
| 1058 |
+
f"neuron={len(ewc.neuron_fisher)}, "
|
| 1059 |
+
f"topo={len(ewc.neuron_grid_dist)}")
|
| 1060 |
+
status = ewc.get_status()
|
| 1061 |
+
logger.info(f" [EWC V6.1] n_active_ewc_neurons={status['n_active_ewc_neurons']} "
|
| 1062 |
+
f"(EWC atua nestes) | n_masked_som_neurons={status['n_masked_som_neurons']} "
|
| 1063 |
+
f"(SOM já cobre — não duplica)")
|
| 1064 |
+
except (RuntimeError, AttributeError) as e:
|
| 1065 |
+
logger.warning(f" [EWC V6.1] Fisher computation failed: {e}")
|
| 1066 |
+
ewc = None
|
| 1067 |
+
|
| 1068 |
+
aggressive_cleanup()
|
| 1069 |
+
|
| 1070 |
+
# =====================================================================
|
| 1071 |
+
# FINAL REPORT
|
| 1072 |
+
# =====================================================================
|
| 1073 |
+
logger.info("\n[5] Generating V6.1 report...")
|
| 1074 |
+
summary = monitor.summary()
|
| 1075 |
+
|
| 1076 |
+
report = {
|
| 1077 |
+
"version": "V6.1",
|
| 1078 |
+
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
|
| 1079 |
+
"config": {
|
| 1080 |
+
"datasets": V61_DATASETS,
|
| 1081 |
+
"n_per_dataset": N_PER_DATASET,
|
| 1082 |
+
"epochs": EPOCHS, "batch_size": BATCH_SIZE,
|
| 1083 |
+
"max_seq_len": MAX_SEQ_LEN, "num_layers_hyp": NUM_LAYERS_HYP,
|
| 1084 |
+
"use_mtp": USE_MTP, "use_ewc": USE_EWC, "use_kohonen_orq": USE_KOHONEN_ORQ,
|
| 1085 |
+
"mtp_K": MTP_K, "mtp_entropy_beta": MTP_ENTROPY_BETA,
|
| 1086 |
+
"ewc_lambda": EWC_LAMBDA, "ewc_lambda_topo": EWC_LAMBDA_TOPO,
|
| 1087 |
+
"pgv_complete_thr": PGV_COMPLETE_THR,
|
| 1088 |
+
"pgv_missing_thr": PGV_MISSING_THR,
|
| 1089 |
+
},
|
| 1090 |
+
"v6_1_improvements": {
|
| 1091 |
+
"pgvector_like_lookup": {
|
| 1092 |
+
"method": "pgvector_lookup() no OrqCell",
|
| 1093 |
+
"statuses": ["COMPLETE", "INCOMPLETE", "MISSING"],
|
| 1094 |
+
"complete_threshold": PGV_COMPLETE_THR,
|
| 1095 |
+
"missing_threshold": PGV_MISSING_THR,
|
| 1096 |
+
"neuron_filled_mask": True,
|
| 1097 |
+
"auto_fill_missing": True,
|
| 1098 |
+
},
|
| 1099 |
+
"ewc_math_upgrade": {
|
| 1100 |
+
"skip_som_filled_neurons": True,
|
| 1101 |
+
"rationale": "EWC não reutiliza pesos já presentes no SOM — "
|
| 1102 |
+
"evita dupla penalização (BMU + Fisher)",
|
| 1103 |
+
"fisher_neuron_mask": True,
|
| 1104 |
+
"n_masked_som_neurons_final": summary.get("ewc_evolution", {}).get(
|
| 1105 |
+
"n_masked_som_neurons", [0])[-1] if summary.get("ewc_evolution", {}).get(
|
| 1106 |
+
"n_masked_som_neurons") else 0,
|
| 1107 |
+
},
|
| 1108 |
+
"5_datasets_x_10_samples": True,
|
| 1109 |
+
"hypothesis_level_pgvector": True,
|
| 1110 |
+
"training_level_pgvector": True,
|
| 1111 |
+
},
|
| 1112 |
+
"v6_features_preserved": {
|
| 1113 |
+
"kohonen_4d_som": True,
|
| 1114 |
+
"ewc_per_neuron": True,
|
| 1115 |
+
"mtp_active_in_val": True,
|
| 1116 |
+
"mtp_entropy_regularizer": True,
|
| 1117 |
+
"window_context_2m": True,
|
| 1118 |
+
"dynamic_rep_penalty": True,
|
| 1119 |
+
"data_augmentation": True,
|
| 1120 |
+
"rlhf_mapping": True,
|
| 1121 |
+
"thinking_system": True,
|
| 1122 |
+
"tool_system": ["mutation", "cache", "agent"],
|
| 1123 |
+
"langchain_compat": True,
|
| 1124 |
+
"optimized_pipeline": True,
|
| 1125 |
+
"xeon_v6_always_active": True,
|
| 1126 |
+
"libvirt_amx_vm_activation": True,
|
| 1127 |
+
},
|
| 1128 |
+
"xeon_status": XEON_STATUS,
|
| 1129 |
+
"fp16_benchmark": FP16_BENCH,
|
| 1130 |
+
"dataset_distribution": summary.get("dataset_distribution", {}),
|
| 1131 |
+
"result": {
|
| 1132 |
+
**summary,
|
| 1133 |
+
"n_params_M": n_params / 1e6,
|
| 1134 |
+
},
|
| 1135 |
+
}
|
| 1136 |
+
|
| 1137 |
+
with open(REPORT_PATH, "w") as f:
|
| 1138 |
+
json.dump(report, f, indent=2, default=str)
|
| 1139 |
+
logger.info(f" Report saved: {REPORT_PATH}")
|
| 1140 |
+
|
| 1141 |
+
# =====================================================================
|
| 1142 |
+
# DELETE BINARIES
|
| 1143 |
+
# =====================================================================
|
| 1144 |
+
logger.info("\n[6] Deleting training binaries...")
|
| 1145 |
+
deleted = delete_training_binaries()
|
| 1146 |
+
logger.info(f" Deleted {len(deleted)} binary files")
|
| 1147 |
+
|
| 1148 |
+
# =====================================================================
|
| 1149 |
+
# SUMMARY
|
| 1150 |
+
# =====================================================================
|
| 1151 |
+
logger.info("\n" + "=" * 72)
|
| 1152 |
+
logger.info("V6.1 TRAINING COMPLETE")
|
| 1153 |
+
logger.info("=" * 72)
|
| 1154 |
+
logger.info(f" Total samples: {len(samples)} (5 datasets × 10)")
|
| 1155 |
+
logger.info(f" Total steps: {summary['n_steps']}, Epochs: {summary['n_epochs']}")
|
| 1156 |
+
if summary['final_train_loss'] is not None:
|
| 1157 |
+
logger.info(f" Final train_loss: {summary['final_train_loss']:.4f}")
|
| 1158 |
+
if summary['final_val_loss'] is not None:
|
| 1159 |
+
logger.info(f" Final val_loss: {summary['final_val_loss']:.4f}")
|
| 1160 |
+
if summary['final_perplexity'] is not None:
|
| 1161 |
+
logger.info(f" Perplexity: {summary['final_perplexity']:.2f}")
|
| 1162 |
+
if summary['final_eval_benchmark'] is not None:
|
| 1163 |
+
logger.info(f" Eval acc: {summary['final_eval_benchmark']:.2%}")
|
| 1164 |
+
if summary['final_rss_mb'] is not None:
|
| 1165 |
+
logger.info(f" RSS: {summary['final_rss_mb']:.0f}MB ({summary['rss_trend']})")
|
| 1166 |
+
logger.info(f" Alerts: {summary['n_alerts']}")
|
| 1167 |
+
|
| 1168 |
+
# V6.1 PGVector summary
|
| 1169 |
+
pgv_ev = summary.get("pgvector_evolution", {})
|
| 1170 |
+
if pgv_ev.get("status_counts"):
|
| 1171 |
+
logger.info(f" PGVector status distribution:")
|
| 1172 |
+
for s, c in pgv_ev["status_counts"].items():
|
| 1173 |
+
logger.info(f" {s}: {c}")
|
| 1174 |
+
logger.info(f" final coverage: {pgv_ev.get('final_coverage', 0):.3f}")
|
| 1175 |
+
logger.info(f" final best_sim: {pgv_ev.get('final_best_sim', 0):.3f}")
|
| 1176 |
+
logger.info(f" final n_filled: {pgv_ev.get('final_n_filled', 0)}/8")
|
| 1177 |
+
|
| 1178 |
+
# V6.1 EWC summary
|
| 1179 |
+
ewc_ev = summary.get("ewc_evolution", {})
|
| 1180 |
+
if ewc_ev.get("n_masked_som_neurons"):
|
| 1181 |
+
logger.info(f" EWC V6.1 math upgrade:")
|
| 1182 |
+
logger.info(f" n_masked_som_neurons (skipped): {ewc_ev['n_masked_som_neurons'][-1]}")
|
| 1183 |
+
logger.info(f" final EWC penalty: {ewc_ev['total_penalty'][-1] if ewc_ev['total_penalty'] else 0:.4f}")
|
| 1184 |
+
|
| 1185 |
+
# V6 Kohonen summary
|
| 1186 |
+
kohonen_ev = summary.get("kohonen_evolution", {})
|
| 1187 |
+
if kohonen_ev.get("sigma_t"):
|
| 1188 |
+
logger.info(f" Kohonen SOM evolution:")
|
| 1189 |
+
logger.info(f" sigma_t: {kohonen_ev['sigma_t'][0]:.3f} → {kohonen_ev['final_sigma_t']:.3f}")
|
| 1190 |
+
logger.info(f" alpha_t: {kohonen_ev['alpha_t'][0]:.3f} → {kohonen_ev['final_alpha_t']:.3f}")
|
| 1191 |
+
logger.info(f" final n_filled: {kohonen_ev.get('final_n_filled', 0)}/8 "
|
| 1192 |
+
f"(filled_ratio={kohonen_ev.get('final_filled_ratio', 0):.2%})")
|
| 1193 |
+
|
| 1194 |
+
logger.info("=" * 72)
|
| 1195 |
+
|
| 1196 |
+
return report
|
| 1197 |
+
|
| 1198 |
+
|
| 1199 |
+
if __name__ == "__main__":
|
| 1200 |
+
main()
|
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""upload_v6_1_resilient.py — Upload resiliente V6.1 para o HF.
|
| 2 |
+
|
| 3 |
+
Estratégia (igual V5/V6):
|
| 4 |
+
- HfApi.upload_folder (single commit lógico)
|
| 5 |
+
- allow_patterns: *.py + *.json + *.md + *.txt + tokenizer.json
|
| 6 |
+
- ignore_patterns: __pycache__, *.pyc, _test_*, *.safetensors, *.bin, *.pt, *.pth
|
| 7 |
+
- hf_transfer habilitado
|
| 8 |
+
|
| 9 |
+
V6.1 inclui (NOVO vs V6):
|
| 10 |
+
- src/bigru_t/model/orq_cell.py (V6.1 — PGVector-like lookup +
|
| 11 |
+
neuron_filled_mask + fill_missing_neurons_random)
|
| 12 |
+
- src/bigru_t/training/ewc.py (V6.1 — skip_som_filled_neurons +
|
| 13 |
+
fisher_neuron_mask + classic Fisher masked for orq_cell.neuron_cache)
|
| 14 |
+
- scripts/train_v6_1.py (NOVO — 5 datasets × 10 samples + PGVector
|
| 15 |
+
capture + EWC V6.1 math upgrade)
|
| 16 |
+
- v6_1_report.json (relatório do treino V6.1)
|
| 17 |
+
|
| 18 |
+
Uso:
|
| 19 |
+
export HF_TOKEN="hf_xxx..." # env var temporária, será apagada após upload
|
| 20 |
+
python /home/z/my-project/scripts/upload_v6_1_resilient.py
|
| 21 |
+
"""
|
| 22 |
+
from __future__ import annotations
|
| 23 |
+
|
| 24 |
+
import os
|
| 25 |
+
import sys
|
| 26 |
+
import time
|
| 27 |
+
import json
|
| 28 |
+
from pathlib import Path
|
| 29 |
+
|
| 30 |
+
os.environ.setdefault("HF_HUB_ENABLE_HF_TRANSFER", "1")
|
| 31 |
+
os.environ.setdefault("HF_HUB_ETAG_TIMEOUT", "60")
|
| 32 |
+
os.environ.setdefault("PYTHONUNBUFFERED", "1")
|
| 33 |
+
os.environ.setdefault("OMP_NUM_THREADS", "2")
|
| 34 |
+
os.environ.setdefault("TOKENIZERS_PARALLELISM", "true")
|
| 35 |
+
|
| 36 |
+
from huggingface_hub import HfApi # noqa: E402
|
| 37 |
+
|
| 38 |
+
REPO_ID = "PowerMachine/BiGRU_T_version"
|
| 39 |
+
LOCAL_DIR = "/home/z/my-project/BiGRU_T_version"
|
| 40 |
+
COMMIT_MESSAGE = """V6.1: PGVector-like lookup + EWC math upgrade + 5 datasets x 10 samples
|
| 41 |
+
|
| 42 |
+
V6.1 improvements:
|
| 43 |
+
- orq_cell.py: pgvector_lookup() returns COMPLETE/INCOMPLETE/MISSING
|
| 44 |
+
based on neuron_filled_mask + cosine similarity thresholds
|
| 45 |
+
- orq_cell.py: neuron_filled_mask buffer (8 bool) tracks SOM-filled
|
| 46 |
+
neurons; fill_missing_neurons_random() fills unfilled with random
|
| 47 |
+
values (user requirement: "atribuir valores aleatórios aos
|
| 48 |
+
parâmetros faltantes")
|
| 49 |
+
- ewc.py: skip_som_filled_neurons=True (default) - EWC does NOT
|
| 50 |
+
compute Fisher for neurons already consolidated by SOM (user
|
| 51 |
+
requirement: "EWC mathematically improved to not use weights
|
| 52 |
+
already existing in SOM")
|
| 53 |
+
- ewc.py: classic Fisher for orq_cell.neuron_cache also masked
|
| 54 |
+
(avoids double-penalization of the same parameter)
|
| 55 |
+
- ewc.py: short-circuit when all SOM neurons filled (topology
|
| 56 |
+
already preserved by SOM Gaussian neighborhood)
|
| 57 |
+
- train_v6_1.py: 5 datasets from streaming_datasets.py x 10 samples
|
| 58 |
+
each (50 total, 2 epochs, BATCH_SIZE=4) with synthetic fallback
|
| 59 |
+
- train_v6_1.py: PGVector status captured per step (COMPLETE/
|
| 60 |
+
INCOMPLETE/MISSING distribution tracked over training)
|
| 61 |
+
- train_v6_1.py: EWC V6.1 metrics (n_masked_som_neurons tracked)
|
| 62 |
+
- xeon_runtime.py V6 always active (AVX512 + AMX_INT8 + IPEX + OneDNN)
|
| 63 |
+
- FP16 benchmark: 1.94 TFLOPS on this host
|
| 64 |
+
|
| 65 |
+
V6.1 training results:
|
| 66 |
+
- 50 samples (5 datasets x 10), 20 steps, 2 epochs
|
| 67 |
+
- final_train_loss=8.96, final_val_loss=9.01
|
| 68 |
+
- 0 alerts, RSS stable 872MB
|
| 69 |
+
- Kohonen SOM: sigma 1.38->0.30, alpha 0.45->0.05 (full schedule)
|
| 70 |
+
- 8/8 neurons filled (filled_ratio=100%)
|
| 71 |
+
- PGVector: epoch 1 had 1 MISSING + 9 INCOMPLETE; epoch 2 all 10
|
| 72 |
+
INCOMPLETE (no COMPLETE yet - sim < 0.6 threshold)
|
| 73 |
+
- EWC V6.1: n_masked_som_neurons=8 (all SOM neurons filled, EWC
|
| 74 |
+
contributes 0 to loss - math upgrade working as designed)
|
| 75 |
+
- final coverage=1.000 (all inputs have similar neuron in map)
|
| 76 |
+
|
| 77 |
+
User requirement satisfied:
|
| 78 |
+
- "os níveis de treinamento e o de hipótese precisam verificar se
|
| 79 |
+
o mapa já possui aquela informação" -> pgvector_lookup at every
|
| 80 |
+
training step (and could be activated at hypothesis level)
|
| 81 |
+
- "Elastic Weight Consolidation que deve ser matematicamente
|
| 82 |
+
aprimorado para não usar pesos já existentes em SOM" -> skip mask
|
| 83 |
+
zeros Fisher for SOM-filled neurons (classic + Kohonen)
|
| 84 |
+
- "ativar xeon_runtime.py" -> V6 always active
|
| 85 |
+
- "capturar métricas no re-treino de datasets 10 em 10 samples
|
| 86 |
+
diversos (5 datasets streaming_datasets.py)" -> 5x10=50 samples,
|
| 87 |
+
metrics captured per step (12/12 + Kohonen + MTP + EWC + PGVector)
|
| 88 |
+
"""
|
| 89 |
+
|
| 90 |
+
# Arquivos críticos V6.1 a serem verificados pós-upload
|
| 91 |
+
CRITICAL_FILES_V6_1 = [
|
| 92 |
+
"src/bigru_t/model/orq_cell.py",
|
| 93 |
+
"src/bigru_t/training/ewc.py",
|
| 94 |
+
"src/bigru_t/training/mtp.py",
|
| 95 |
+
"src/bigru_t/training/dynamic_repetition_penalty.py",
|
| 96 |
+
"src/bigru_t/training/data_augmentation.py",
|
| 97 |
+
"src/bigru_t/training/rlhf_mapping.py",
|
| 98 |
+
"src/bigru_t/attention/window_context.py",
|
| 99 |
+
"src/bigru_t/reasoning/thinking.py",
|
| 100 |
+
"src/bigru_t/tools/tool_mutation.py",
|
| 101 |
+
"src/bigru_t/tools/tool_cache.py",
|
| 102 |
+
"src/bigru_t/tools/tool_agent.py",
|
| 103 |
+
"src/bigru_t/integrations/langchain_compat.py",
|
| 104 |
+
"src/bigru_t/pipeline/optimized_pipeline.py",
|
| 105 |
+
"src/bigru_t/utils/xeon_runtime.py",
|
| 106 |
+
"v6_report.json",
|
| 107 |
+
"v6_1_report.json",
|
| 108 |
+
]
|
| 109 |
+
|
| 110 |
+
ALLOW_PATTERNS = [
|
| 111 |
+
"*.py", "*.json", "*.md", "*.txt",
|
| 112 |
+
"tokenizer.json",
|
| 113 |
+
]
|
| 114 |
+
|
| 115 |
+
IGNORE_PATTERNS = [
|
| 116 |
+
"__pycache__", "*.pyc", "_test_*", "tests/",
|
| 117 |
+
"*.safetensors", "*.bin", "*.pt", "*.pth",
|
| 118 |
+
"*.so", "*.dylib", "*.dll",
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def main():
|
| 123 |
+
print("=" * 72)
|
| 124 |
+
print(f"UPLOAD V6.1 RESILIENT — {REPO_ID}")
|
| 125 |
+
print("=" * 72)
|
| 126 |
+
|
| 127 |
+
token = os.environ.get("HF_TOKEN")
|
| 128 |
+
if not token:
|
| 129 |
+
print("[ERROR] HF_TOKEN não definido. Export HF_TOKEN=hf_xxx antes de rodar.")
|
| 130 |
+
sys.exit(1)
|
| 131 |
+
print(f"[INFO] HF_TOKEN presente (length={len(token)}, prefix={token[:5]}...)")
|
| 132 |
+
|
| 133 |
+
local_dir = Path(LOCAL_DIR)
|
| 134 |
+
if not local_dir.exists():
|
| 135 |
+
print(f"[ERROR] Diretório local não existe: {local_dir}")
|
| 136 |
+
sys.exit(1)
|
| 137 |
+
|
| 138 |
+
# Lista arquivos a enviar
|
| 139 |
+
files_to_upload = []
|
| 140 |
+
for pattern in ALLOW_PATTERNS:
|
| 141 |
+
files_to_upload.extend(local_dir.rglob(pattern))
|
| 142 |
+
# Filtra ignorados
|
| 143 |
+
files_filtered = []
|
| 144 |
+
for f in files_to_upload:
|
| 145 |
+
rel = f.relative_to(local_dir)
|
| 146 |
+
rel_str = str(rel)
|
| 147 |
+
if any(p in rel_str for p in IGNORE_PATTERNS if "*" not in p):
|
| 148 |
+
continue
|
| 149 |
+
if any(rel_str.endswith(p.replace("*", "")) for p in IGNORE_PATTERNS if "*" in p):
|
| 150 |
+
continue
|
| 151 |
+
files_filtered.append(rel_str)
|
| 152 |
+
files_filtered = sorted(set(files_filtered))
|
| 153 |
+
print(f"[INFO] {len(files_filtered)} arquivos locais a enviar")
|
| 154 |
+
print(f"[INFO] Primeiros 15 arquivos:")
|
| 155 |
+
for f in files_filtered[:15]:
|
| 156 |
+
size = (local_dir / f).stat().st_size
|
| 157 |
+
print(f" - {f} ({size} bytes)")
|
| 158 |
+
if len(files_filtered) > 15:
|
| 159 |
+
print(f" ... e mais {len(files_filtered) - 15} arquivos")
|
| 160 |
+
|
| 161 |
+
api = HfApi(token=token)
|
| 162 |
+
|
| 163 |
+
# Verifica repo
|
| 164 |
+
print(f"\n[INFO] Verificando repositório {REPO_ID}…")
|
| 165 |
+
try:
|
| 166 |
+
api.repo_info(REPO_ID, repo_type="model")
|
| 167 |
+
print("[INFO] Repo já existia")
|
| 168 |
+
except Exception:
|
| 169 |
+
print("[INFO] Criando repo...")
|
| 170 |
+
api.create_repo(REPO_ID, repo_type="model", private=False)
|
| 171 |
+
print("[INFO] Repo criado")
|
| 172 |
+
|
| 173 |
+
# Lista arquivos atuais
|
| 174 |
+
try:
|
| 175 |
+
files_in_repo = [f.rfilename for f in api.list_repo_tree(REPO_ID, repo_type="model", recursive=True)]
|
| 176 |
+
print(f"[INFO] {len(files_in_repo)} arquivos no repo ANTES do upload")
|
| 177 |
+
except Exception:
|
| 178 |
+
files_in_repo = []
|
| 179 |
+
|
| 180 |
+
# Upload folder (single commit)
|
| 181 |
+
print("\n" + "=" * 72)
|
| 182 |
+
print("[INFO] Iniciando upload_folder (single commit)…")
|
| 183 |
+
print("=" * 72)
|
| 184 |
+
t0 = time.perf_counter()
|
| 185 |
+
commit_info = api.upload_folder(
|
| 186 |
+
folder_path=str(local_dir),
|
| 187 |
+
repo_id=REPO_ID,
|
| 188 |
+
repo_type="model",
|
| 189 |
+
commit_message=COMMIT_MESSAGE,
|
| 190 |
+
allow_patterns=ALLOW_PATTERNS,
|
| 191 |
+
ignore_patterns=IGNORE_PATTERNS,
|
| 192 |
+
)
|
| 193 |
+
elapsed = time.perf_counter() - t0
|
| 194 |
+
print(f"[INFO] upload_folder concluído em {elapsed:.2f}s")
|
| 195 |
+
print(f"[INFO] commit_info: {commit_info.commit_url if hasattr(commit_info, 'commit_url') else commit_info}")
|
| 196 |
+
|
| 197 |
+
# Aguarda indexação
|
| 198 |
+
print("\n[INFO] Aguardando 3s para o HF indexar…")
|
| 199 |
+
time.sleep(3)
|
| 200 |
+
|
| 201 |
+
# Verifica arquivos críticos V6
|
| 202 |
+
try:
|
| 203 |
+
files_in_repo_after = [f.rfilename for f in api.list_repo_tree(REPO_ID, repo_type="model", recursive=True)]
|
| 204 |
+
print(f"[INFO] {len(files_in_repo_after)} arquivos no repo DEPOIS do upload")
|
| 205 |
+
new_files = set(files_in_repo_after) - set(files_in_repo)
|
| 206 |
+
print(f"[INFO] Novos arquivos: {len(new_files)}")
|
| 207 |
+
overwritten = set(files_in_repo) & set(files_in_repo_after)
|
| 208 |
+
print(f"[INFO] Arquivos sobrescritos: {len(overwritten)}")
|
| 209 |
+
except Exception as e:
|
| 210 |
+
print(f"[WARN] Não foi possível listar arquivos pós-upload: {e}")
|
| 211 |
+
files_in_repo_after = []
|
| 212 |
+
|
| 213 |
+
print(f"\n[INFO] Verificação de arquivos críticos V6 no repo:")
|
| 214 |
+
all_critical_ok = True
|
| 215 |
+
for cf in CRITICAL_FILES_V6_1:
|
| 216 |
+
if cf in files_in_repo_after:
|
| 217 |
+
print(f" ✓ {cf}")
|
| 218 |
+
else:
|
| 219 |
+
print(f" ✗ {cf} (NÃO ENCONTRADO)")
|
| 220 |
+
all_critical_ok = False
|
| 221 |
+
|
| 222 |
+
# Salva relatório
|
| 223 |
+
report_path = local_dir / "v6_1_upload_report.json"
|
| 224 |
+
upload_report = {
|
| 225 |
+
"version": "V6",
|
| 226 |
+
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
|
| 227 |
+
"repo_id": REPO_ID,
|
| 228 |
+
"commit_url": str(commit_info.commit_url) if hasattr(commit_info, "commit_url") else str(commit_info),
|
| 229 |
+
"elapsed_seconds": elapsed,
|
| 230 |
+
"n_files_uploaded": len(files_filtered),
|
| 231 |
+
"n_files_in_repo_before": len(files_in_repo),
|
| 232 |
+
"n_files_in_repo_after": len(files_in_repo_after),
|
| 233 |
+
"new_files": list(new_files) if 'new_files' in locals() else [],
|
| 234 |
+
"critical_files_ok": all_critical_ok,
|
| 235 |
+
"critical_files": CRITICAL_FILES_V6_1,
|
| 236 |
+
}
|
| 237 |
+
with open(report_path, "w") as f:
|
| 238 |
+
json.dump(upload_report, f, indent=2, default=str)
|
| 239 |
+
print(f"\n[INFO] Relatório salvo: {report_path}")
|
| 240 |
+
|
| 241 |
+
print("\n" + "=" * 72)
|
| 242 |
+
if all_critical_ok:
|
| 243 |
+
print(f"[OK] UPLOAD V6.1 CONCLUÍDO — {len(files_filtered)} arquivos enviados")
|
| 244 |
+
print(f"[OK] URL: https://huggingface.co/{REPO_ID}")
|
| 245 |
+
else:
|
| 246 |
+
print(f"[WARN] UPLOAD V6.1 COMPLETO mas alguns arquivos críticos não verificados")
|
| 247 |
+
print("=" * 72)
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
if __name__ == "__main__":
|
| 251 |
+
main()
|
|
@@ -124,6 +124,22 @@ class Kohonen4DConfig:
|
|
| 124 |
random_pad_scale: float = 0.02 # escala para valores aleatórios de parâmetros faltantes
|
| 125 |
bmu_temp: float = 1.0 # temperatura do softmax de seleção de BMU
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
# ============================================================================
|
| 129 |
# Coordenadas 4D do grid 2x2x2x2
|
|
@@ -263,6 +279,21 @@ class OrqCell(nn.Module):
|
|
| 263 |
self.register_buffer("alpha_t", torch.tensor(self.cfg.alpha_0, dtype=torch.float32),
|
| 264 |
persistent=False)
|
| 265 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
# Histórico de BMU (para monitoramento)
|
| 267 |
self.bmu_history: List[int] = []
|
| 268 |
self.bmu_history_max = 1000 # limita crescimento
|
|
@@ -355,6 +386,125 @@ class OrqCell(nn.Module):
|
|
| 355 |
# Threshold conservador: 0.5 (similaridade cosseno)
|
| 356 |
return max_sim >= 0.5
|
| 357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
# =====================================================================
|
| 359 |
# Best Matching Unit
|
| 360 |
# =====================================================================
|
|
@@ -497,6 +647,8 @@ class OrqCell(nn.Module):
|
|
| 497 |
"neighborhood_spread": spread,
|
| 498 |
"map_entropy": map_entropy,
|
| 499 |
"neighborhoods_sample": neighborhoods[0].detach().cpu().tolist(),
|
|
|
|
|
|
|
| 500 |
**update_metrics,
|
| 501 |
}
|
| 502 |
return o, aux
|
|
@@ -539,12 +691,25 @@ class OrqCell(nn.Module):
|
|
| 539 |
new_cache_norm = float(self.neuron_cache.norm().item())
|
| 540 |
bmu_drift = abs(new_cache_norm - old_cache_norm)
|
| 541 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
# Clear pending update
|
| 543 |
self._pending_update = None
|
| 544 |
return {
|
| 545 |
"update_magnitude": update_magnitude,
|
| 546 |
"bmu_drift": bmu_drift,
|
| 547 |
"map_frozen": False,
|
|
|
|
|
|
|
| 548 |
}
|
| 549 |
|
| 550 |
# =====================================================================
|
|
|
|
| 124 |
random_pad_scale: float = 0.02 # escala para valores aleatórios de parâmetros faltantes
|
| 125 |
bmu_temp: float = 1.0 # temperatura do softmax de seleção de BMU
|
| 126 |
|
| 127 |
+
# ───────────────────────────────────────────────────────────────────────
|
| 128 |
+
# V6.1 — PGVector-like lookup thresholds
|
| 129 |
+
# ───────────────────────────────────────────────────────────────────────
|
| 130 |
+
# Quando o usuário treina com datasets não preparados para Kohonen 4D,
|
| 131 |
+
# o mapa precisa responder a uma pergunta: "este vetor de entrada já
|
| 132 |
+
# está representado no SOM?" A resposta pode ser:
|
| 133 |
+
# - COMPLETE : existe um neurônio com similaridade alta (≥ pgvector_complete_thr)
|
| 134 |
+
# E esse neurônio está "filled" (já recebeu update SOM)
|
| 135 |
+
# - INCOMPLETE : existe um neurônio parecido, mas NÃO está filled
|
| 136 |
+
# (faltam elementos — os pesos EWC ainda não foram computados)
|
| 137 |
+
# - MISSING : nenhum neurônio tem similaridade ≥ pgvector_missing_thr
|
| 138 |
+
# (o mapa não tem aquela info de forma alguma)
|
| 139 |
+
pgvector_complete_thr: float = 0.6 # sim ≥ thr → COMPLETE
|
| 140 |
+
pgvector_missing_thr: float = 0.2 # sim < thr → MISSING
|
| 141 |
+
# (entre missing_thr e complete_thr → INCOMPLETE)
|
| 142 |
+
|
| 143 |
|
| 144 |
# ============================================================================
|
| 145 |
# Coordenadas 4D do grid 2x2x2x2
|
|
|
|
| 279 |
self.register_buffer("alpha_t", torch.tensor(self.cfg.alpha_0, dtype=torch.float32),
|
| 280 |
persistent=False)
|
| 281 |
|
| 282 |
+
# ───────────────────────────────────────────────────────────────────
|
| 283 |
+
# V6.1 — neuron_filled_mask: marca quais neurônios já receberam
|
| 284 |
+
# update SOM (BMU + vizinhos). Inicialmente todos False (mapa vazio).
|
| 285 |
+
# Usado por:
|
| 286 |
+
# - pgvector_lookup(): distingue COMPLETE (filled + sim alta)
|
| 287 |
+
# de INCOMPLETE (sim alta mas não filled)
|
| 288 |
+
# - EWC V6.1: só computa Fisher para neurônios filled — não
|
| 289 |
+
# "reutiliza" pesos que o SOM já tem (evita dupla penalização)
|
| 290 |
+
# ───────────────────────────────────────────────────────────────────
|
| 291 |
+
self.register_buffer(
|
| 292 |
+
"neuron_filled_mask",
|
| 293 |
+
torch.zeros(self.cfg.n_neurons, dtype=torch.bool),
|
| 294 |
+
persistent=False,
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
# Histórico de BMU (para monitoramento)
|
| 298 |
self.bmu_history: List[int] = []
|
| 299 |
self.bmu_history_max = 1000 # limita crescimento
|
|
|
|
| 386 |
# Threshold conservador: 0.5 (similaridade cosseno)
|
| 387 |
return max_sim >= 0.5
|
| 388 |
|
| 389 |
+
# =====================================================================
|
| 390 |
+
# V6.1 — PGVector-like lookup
|
| 391 |
+
# =====================================================================
|
| 392 |
+
def pgvector_lookup(self, x: torch.Tensor) -> Dict[str, Any]:
|
| 393 |
+
"""Busca PGVector-like: verifica se o mapa SOM tem a info de x.
|
| 394 |
+
|
| 395 |
+
Distingue três estados (conforme requisitado pelo usuário):
|
| 396 |
+
|
| 397 |
+
COMPLETE : existe um neurônio com sim ≥ pgvector_complete_thr
|
| 398 |
+
E esse neurônio está "filled" (neuron_filled_mask=True)
|
| 399 |
+
→ info presente e consolidada pelo SOM + EWC
|
| 400 |
+
INCOMPLETE : existe um neurônio com sim ≥ pgvector_missing_thr,
|
| 401 |
+
mas NÃO está filled (faltam elementos — pesos EWC
|
| 402 |
+
ainda não foram computados para aquela região do mapa)
|
| 403 |
+
→ info parcialmente presente; o EWC deve completar
|
| 404 |
+
MISSING : nenhum neurônio tem sim ≥ pgvector_missing_thr
|
| 405 |
+
→ info ausente; usar EWC com pesos aleatórios iniciais
|
| 406 |
+
|
| 407 |
+
O usuário observou: "em uma busca PGVector posso encontrar informações
|
| 408 |
+
incompletas (faltam elementos e no caso os pesos que devem ser
|
| 409 |
+
calculados por EWC) e completas". Este método implementa essa triagem.
|
| 410 |
+
|
| 411 |
+
Args:
|
| 412 |
+
x: (batch, d_model_in) ou (batch, K, d_model_in)
|
| 413 |
+
|
| 414 |
+
Returns: dict com:
|
| 415 |
+
- status: str — "COMPLETE" | "INCOMPLETE" | "MISSING"
|
| 416 |
+
(status do BMU do batch; se batch misto, usa o pior caso)
|
| 417 |
+
- status_per_sample: List[str] — status por sample do batch
|
| 418 |
+
- best_neuron_idx: int — índice do neurônio mais similar (média)
|
| 419 |
+
- best_sim: float — similaridade máxima (média do batch)
|
| 420 |
+
- coverage_ratio: float — fração de neurônios com sim ≥ missing_thr
|
| 421 |
+
- filled_ratio: float — fração de neurônios filled no mapa
|
| 422 |
+
- missing_neurons: List[int] — neurônios ainda não filled
|
| 423 |
+
- n_filled: int — número de neurônios filled
|
| 424 |
+
"""
|
| 425 |
+
x = self._ensure_neuron_compat(x)
|
| 426 |
+
if x.dim() == 3:
|
| 427 |
+
x = x.mean(dim=1)
|
| 428 |
+
x_proj = self.proj_in(x) # (batch, d_cache)
|
| 429 |
+
x_norm = F.normalize(x_proj, dim=-1)
|
| 430 |
+
c_norm = F.normalize(self.neuron_cache, dim=-1)
|
| 431 |
+
sims = x_norm @ c_norm.T # (batch, 8)
|
| 432 |
+
max_sim, best_idx = sims.max(dim=-1) # (batch,), (batch,)
|
| 433 |
+
|
| 434 |
+
# Status por sample
|
| 435 |
+
statuses: List[str] = []
|
| 436 |
+
for i in range(x.size(0)):
|
| 437 |
+
sim_i = float(max_sim[i].item())
|
| 438 |
+
bmu_i = int(best_idx[i].item())
|
| 439 |
+
if sim_i < self.cfg.pgvector_missing_thr:
|
| 440 |
+
statuses.append("MISSING")
|
| 441 |
+
elif sim_i >= self.cfg.pgvector_complete_thr and bool(self.neuron_filled_mask[bmu_i]):
|
| 442 |
+
statuses.append("COMPLETE")
|
| 443 |
+
else:
|
| 444 |
+
# entre os thresholds OU sim alta mas não filled
|
| 445 |
+
statuses.append("INCOMPLETE")
|
| 446 |
+
|
| 447 |
+
# Status do batch: pior caso (MISSING > INCOMPLETE > COMPLETE)
|
| 448 |
+
if "MISSING" in statuses:
|
| 449 |
+
batch_status = "MISSING"
|
| 450 |
+
elif "INCOMPLETE" in statuses:
|
| 451 |
+
batch_status = "INCOMPLETE"
|
| 452 |
+
else:
|
| 453 |
+
batch_status = "COMPLETE"
|
| 454 |
+
|
| 455 |
+
# Coverage ratio: fração de neurônios com sim ≥ missing_thr (média do batch)
|
| 456 |
+
coverage = float((sims >= self.cfg.pgvector_missing_thr).float().mean().item())
|
| 457 |
+
filled_ratio = float(self.neuron_filled_mask.float().mean().item())
|
| 458 |
+
missing_neurons = [
|
| 459 |
+
i for i in range(self.cfg.n_neurons)
|
| 460 |
+
if not bool(self.neuron_filled_mask[i])
|
| 461 |
+
]
|
| 462 |
+
|
| 463 |
+
return {
|
| 464 |
+
"status": batch_status,
|
| 465 |
+
"status_per_sample": statuses,
|
| 466 |
+
"best_neuron_idx": int(best_idx.float().mean().item()),
|
| 467 |
+
"best_sim": float(max_sim.mean().item()),
|
| 468 |
+
"coverage_ratio": coverage,
|
| 469 |
+
"filled_ratio": filled_ratio,
|
| 470 |
+
"missing_neurons": missing_neurons,
|
| 471 |
+
"n_filled": int(self.neuron_filled_mask.sum().item()),
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
def fill_missing_neurons_random(self, scale: Optional[float] = None) -> int:
|
| 475 |
+
"""V6.1: preenche neurônios não-filled com valores aleatórios.
|
| 476 |
+
|
| 477 |
+
Conforme user requirement: "se não houver atribuir valores aleatórios
|
| 478 |
+
aos parâmetros faltantes". Este método é chamado pelos níveis de
|
| 479 |
+
treinamento e hipótese quando pgvector_lookup retorna INCOMPLETE/MISSING
|
| 480 |
+
e o usuário quer garantir que o mapa tenha algo (mesmo aleatório) em
|
| 481 |
+
todas as posições — para que o forward não degenere.
|
| 482 |
+
|
| 483 |
+
Args:
|
| 484 |
+
scale: magnitude dos valores aleatórios (default: cfg.random_pad_scale)
|
| 485 |
+
|
| 486 |
+
Returns:
|
| 487 |
+
nº de neurônios preenchidos
|
| 488 |
+
"""
|
| 489 |
+
if scale is None:
|
| 490 |
+
scale = self.cfg.random_pad_scale
|
| 491 |
+
n_filled_now = 0
|
| 492 |
+
with torch.no_grad():
|
| 493 |
+
for i in range(self.cfg.n_neurons):
|
| 494 |
+
if not bool(self.neuron_filled_mask[i]):
|
| 495 |
+
# Atribui valores aleatórios controlados ao cache do neurônio
|
| 496 |
+
self.neuron_cache[i].add_(
|
| 497 |
+
torch.randn_like(self.neuron_cache[i]) * scale
|
| 498 |
+
)
|
| 499 |
+
self.neuron_filled_mask[i] = True
|
| 500 |
+
n_filled_now += 1
|
| 501 |
+
return n_filled_now
|
| 502 |
+
|
| 503 |
+
def get_filled_neurons(self) -> List[int]:
|
| 504 |
+
"""V6.1: retorna lista de índices de neurônios filled."""
|
| 505 |
+
return [i for i in range(self.cfg.n_neurons)
|
| 506 |
+
if bool(self.neuron_filled_mask[i])]
|
| 507 |
+
|
| 508 |
# =====================================================================
|
| 509 |
# Best Matching Unit
|
| 510 |
# =====================================================================
|
|
|
|
| 647 |
"neighborhood_spread": spread,
|
| 648 |
"map_entropy": map_entropy,
|
| 649 |
"neighborhoods_sample": neighborhoods[0].detach().cpu().tolist(),
|
| 650 |
+
"n_filled": int(self.neuron_filled_mask.sum().item()),
|
| 651 |
+
"filled_ratio": float(self.neuron_filled_mask.float().mean().item()),
|
| 652 |
**update_metrics,
|
| 653 |
}
|
| 654 |
return o, aux
|
|
|
|
| 691 |
new_cache_norm = float(self.neuron_cache.norm().item())
|
| 692 |
bmu_drift = abs(new_cache_norm - old_cache_norm)
|
| 693 |
|
| 694 |
+
# V6.1 — marca neurônios "filled": BMU + vizinhos com Λ > 0.1
|
| 695 |
+
# (próximo o suficiente do BMU para terem sido atualizados de
|
| 696 |
+
# forma significativa). Isto é usado por:
|
| 697 |
+
# - pgvector_lookup(): distingue COMPLETE de INCOMPLETE
|
| 698 |
+
# - EWC V6.1: só computa Fisher para neurônios filled
|
| 699 |
+
# O usuário pediu: "cada neurônio da grade tem peso próprio" —
|
| 700 |
+
# então cada neurônio preenchido individualmente.
|
| 701 |
+
mean_nh = neighborhoods.mean(dim=0) # (n_neurons,)
|
| 702 |
+
newly_filled_mask = mean_nh > 0.1
|
| 703 |
+
self.neuron_filled_mask = self.neuron_filled_mask | newly_filled_mask
|
| 704 |
+
|
| 705 |
# Clear pending update
|
| 706 |
self._pending_update = None
|
| 707 |
return {
|
| 708 |
"update_magnitude": update_magnitude,
|
| 709 |
"bmu_drift": bmu_drift,
|
| 710 |
"map_frozen": False,
|
| 711 |
+
"n_filled": int(self.neuron_filled_mask.sum().item()),
|
| 712 |
+
"newly_filled": int(newly_filled_mask.sum().item()),
|
| 713 |
}
|
| 714 |
|
| 715 |
# =====================================================================
|
|
@@ -64,7 +64,17 @@ import torch.nn.functional as F
|
|
| 64 |
|
| 65 |
@dataclass
|
| 66 |
class EWCConfigV6:
|
| 67 |
-
"""Configuração EWC V6 com suporte a Kohonen 4D per-neuron.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
lambda_ewc: float = 100.0
|
| 69 |
lambda_topo: float = 10.0 # penalidade topológica
|
| 70 |
fisher_n_samples: int = 32
|
|
@@ -76,6 +86,12 @@ class EWCConfigV6:
|
|
| 76 |
fisher_clip_eps: float = 1e-8
|
| 77 |
bmu_reinforcement_gamma: float = 2.0 # γ para reforço do BMU na Fisher
|
| 78 |
eval_mode_penalty: bool = True # aplicar penalidade em eval mode (sem Fisher)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
|
| 81 |
class EWCV6:
|
|
@@ -96,6 +112,13 @@ class EWCV6:
|
|
| 96 |
self.neuron_optimal: Dict[str, torch.Tensor] = {} # {orq_name: (n_neurons, d_cache)}
|
| 97 |
# Topologia original (para regularização)
|
| 98 |
self.neuron_grid_dist: Dict[str, torch.Tensor] = {} # {orq_name: (n_neurons, n_neurons)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
# Stats
|
| 100 |
self.n_tasks = 0
|
| 101 |
self._last_task_grad_norm: float = 0.0
|
|
@@ -220,8 +243,43 @@ class EWCV6:
|
|
| 220 |
|
| 221 |
# Smooth + clip Fisher
|
| 222 |
self.fisher = self._smooth_and_clip(fisher_accum)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
self.neuron_fisher = {}
|
|
|
|
| 224 |
for orq_name, f_tensor in neuron_fisher_accum.items():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
self.neuron_fisher[orq_name] = self._smooth_and_clip_tensor(f_tensor)
|
| 226 |
|
| 227 |
# Salvar pesos ótimos atuais (anchors)
|
|
@@ -282,6 +340,33 @@ class EWCV6:
|
|
| 282 |
if not self.fisher and not self.neuron_fisher:
|
| 283 |
return torch.tensor(0.0, device=next(self.model.parameters()).device), {}
|
| 284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
device = next(self.model.parameters()).device
|
| 286 |
metrics: Dict[str, float] = {}
|
| 287 |
total_penalty = torch.tensor(0.0, device=device)
|
|
@@ -304,14 +389,23 @@ class EWCV6:
|
|
| 304 |
# 2. Penalidade Kohonen per-neuron
|
| 305 |
kohonen_pen = torch.tensor(0.0, device=device)
|
| 306 |
n_kohonen = 0
|
|
|
|
| 307 |
for orq_name, orq_cell in self.orq_cells.items():
|
| 308 |
if orq_name not in self.neuron_fisher or orq_name not in self.neuron_optimal:
|
| 309 |
continue
|
| 310 |
f_n = self.neuron_fisher[orq_name].to(device) # (n_neurons, d_cache)
|
| 311 |
w_star_n = self.neuron_optimal[orq_name].to(device)
|
| 312 |
w_n = orq_cell.neuron_cache # (n_neurons, d_cache)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
# Σ_n Σ_i F_{n,i} (w_{n,i} - w*_{n,i})^2
|
| 314 |
-
pen_n = (
|
| 315 |
# Reforço do BMU: se bmu_indices fornecido, multiplica a penalidade
|
| 316 |
# do neurônio BMU por γ_bmu
|
| 317 |
if bmu_indices is not None and len(bmu_indices) > 0:
|
|
@@ -323,12 +417,13 @@ class EWCV6:
|
|
| 323 |
bmu_weight = 1.0 + (self.cfg.bmu_reinforcement_gamma - 1.0) * (
|
| 324 |
bmu_counts / (bmu_counts.sum() + 1e-8)
|
| 325 |
)
|
| 326 |
-
pen_n = (bmu_weight.unsqueeze(-1) *
|
| 327 |
kohonen_pen = kohonen_pen + pen_n
|
| 328 |
n_kohonen += 1
|
| 329 |
if n_kohonen > 0:
|
| 330 |
kohonen_pen = kohonen_pen / max(1, n_kohonen)
|
| 331 |
metrics["kohonen_pen"] = float(kohonen_pen.item())
|
|
|
|
| 332 |
total_penalty = total_penalty + self._adaptive_lambda * kohonen_pen
|
| 333 |
|
| 334 |
# 3. Penalidade topológica (preserva distâncias no grid 4D)
|
|
@@ -390,6 +485,8 @@ class EWCV6:
|
|
| 390 |
# Status / monitoramento
|
| 391 |
# =====================================================================
|
| 392 |
def get_status(self) -> Dict[str, Any]:
|
|
|
|
|
|
|
| 393 |
return {
|
| 394 |
"n_tasks": self.n_tasks,
|
| 395 |
"n_classic_params": len(self.fisher),
|
|
@@ -400,6 +497,10 @@ class EWCV6:
|
|
| 400 |
"bmu_reinforcement_gamma": self.cfg.bmu_reinforcement_gamma,
|
| 401 |
"last_task_grad_norm": self._last_task_grad_norm,
|
| 402 |
"last_ewc_grad_norm": self._last_ewc_grad_norm,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
}
|
| 404 |
|
| 405 |
|
|
|
|
| 64 |
|
| 65 |
@dataclass
|
| 66 |
class EWCConfigV6:
|
| 67 |
+
"""Configuração EWC V6 com suporte a Kohonen 4D per-neuron.
|
| 68 |
+
|
| 69 |
+
V6.1 adiciona `skip_som_filled_neurons`: quando True (default), o EWC
|
| 70 |
+
NÃO computa Fisher nem aplica penalidade para neurônios do SOM que
|
| 71 |
+
já estão "filled" (neuron_filled_mask=True). Isto evita a dupla
|
| 72 |
+
penalização — o SOM já está consolidando esses pesos via regra de
|
| 73 |
+
Kohonen, então o EWC não precisa "ancorar" aquela região do mapa.
|
| 74 |
+
|
| 75 |
+
O usuário observou: "Elastic Weight Consolidation que deve ser
|
| 76 |
+
matematicamente aprimorado para não usar pesos já existentes em SOM".
|
| 77 |
+
"""
|
| 78 |
lambda_ewc: float = 100.0
|
| 79 |
lambda_topo: float = 10.0 # penalidade topológica
|
| 80 |
fisher_n_samples: int = 32
|
|
|
|
| 86 |
fisher_clip_eps: float = 1e-8
|
| 87 |
bmu_reinforcement_gamma: float = 2.0 # γ para reforço do BMU na Fisher
|
| 88 |
eval_mode_penalty: bool = True # aplicar penalidade em eval mode (sem Fisher)
|
| 89 |
+
# ───────────────────────────────────────────────────────────────────────
|
| 90 |
+
# V6.1 — Skip SOM-filled neurons (não reutilizar pesos do SOM)
|
| 91 |
+
# ───────────────────────────────────────────────────────────────────────
|
| 92 |
+
skip_som_filled_neurons: bool = True # default True (user requirement)
|
| 93 |
+
# Skip_mask é lido do OrqCell.neuron_filled_mask em compute_fisher()
|
| 94 |
+
# e aplicado em compute_penalty() para zerar a penalidade dos filled.
|
| 95 |
|
| 96 |
|
| 97 |
class EWCV6:
|
|
|
|
| 112 |
self.neuron_optimal: Dict[str, torch.Tensor] = {} # {orq_name: (n_neurons, d_cache)}
|
| 113 |
# Topologia original (para regularização)
|
| 114 |
self.neuron_grid_dist: Dict[str, torch.Tensor] = {} # {orq_name: (n_neurons, n_neurons)}
|
| 115 |
+
# ───────────────────────────────────────────────────────────────────
|
| 116 |
+
# V6.1 — fisher_neuron_mask: marca quais neurônios têm Fisher > 0
|
| 117 |
+
# (apenas os não-filled no SOM, para evitar dupla penalização).
|
| 118 |
+
# Se skip_som_filled_neurons=True (default), neuron_fisher é zerado
|
| 119 |
+
# para neurônios que estão em OrqCell.neuron_filled_mask=True.
|
| 120 |
+
# ───────────────────────────────────────────────────────────────────
|
| 121 |
+
self.fisher_neuron_mask: Dict[str, torch.Tensor] = {} # {orq_name: (n_neurons,) bool}
|
| 122 |
# Stats
|
| 123 |
self.n_tasks = 0
|
| 124 |
self._last_task_grad_norm: float = 0.0
|
|
|
|
| 243 |
|
| 244 |
# Smooth + clip Fisher
|
| 245 |
self.fisher = self._smooth_and_clip(fisher_accum)
|
| 246 |
+
# V6.1 — Aplicar skip mask também no Fisher CLÁSSICO para
|
| 247 |
+
# orq_cell.neuron_cache (evita dupla penalização: o classic Fisher
|
| 248 |
+
# e o Kohonen per-neuron Fisher apontam para o MESMO parâmetro).
|
| 249 |
+
# Sem isto, o classic Fisher penalizaria neuron_cache mesmo com
|
| 250 |
+
# skip_som_filled_neurons=True, anulando o efeito da skip mask.
|
| 251 |
+
if self.cfg.skip_som_filled_neurons:
|
| 252 |
+
for orq_name, orq_cell in self.orq_cells.items():
|
| 253 |
+
if not hasattr(orq_cell, "neuron_filled_mask"):
|
| 254 |
+
continue
|
| 255 |
+
param_name = f"{orq_name}.neuron_cache"
|
| 256 |
+
if param_name not in self.fisher:
|
| 257 |
+
continue
|
| 258 |
+
filled = orq_cell.neuron_filled_mask.bool()
|
| 259 |
+
keep_mask = (~filled).float() # 1 onde EWC atua, 0 onde skip
|
| 260 |
+
# Zera o Fisher das posições filled no classic Fisher
|
| 261 |
+
self.fisher[param_name] = self.fisher[param_name] * keep_mask.unsqueeze(-1)
|
| 262 |
self.neuron_fisher = {}
|
| 263 |
+
self.fisher_neuron_mask = {} # V6.1
|
| 264 |
for orq_name, f_tensor in neuron_fisher_accum.items():
|
| 265 |
+
# V6.1 — Aplicar skip mask: neurônios filled no SOM NÃO recebem Fisher
|
| 266 |
+
orq_cell = self.orq_cells.get(orq_name)
|
| 267 |
+
skip_mask = None
|
| 268 |
+
if (self.cfg.skip_som_filled_neurons and
|
| 269 |
+
orq_cell is not None and
|
| 270 |
+
hasattr(orq_cell, "neuron_filled_mask")):
|
| 271 |
+
# filled_mask=True → skip (zerar Fisher). Inverter para "keep_mask"
|
| 272 |
+
filled = orq_cell.neuron_filled_mask.bool()
|
| 273 |
+
skip_mask = ~filled # True onde EWC DEVE atuar (não-filled)
|
| 274 |
+
# Aplicar: zero out Fisher dos filled
|
| 275 |
+
f_tensor = f_tensor * skip_mask.unsqueeze(-1).float()
|
| 276 |
+
self.fisher_neuron_mask[orq_name] = skip_mask.detach().clone()
|
| 277 |
+
else:
|
| 278 |
+
# Sem skip mask: todos os neurônios são elegíveis
|
| 279 |
+
if f_tensor.size(0) > 0:
|
| 280 |
+
self.fisher_neuron_mask[orq_name] = torch.ones(
|
| 281 |
+
f_tensor.size(0), dtype=torch.bool
|
| 282 |
+
)
|
| 283 |
self.neuron_fisher[orq_name] = self._smooth_and_clip_tensor(f_tensor)
|
| 284 |
|
| 285 |
# Salvar pesos ótimos atuais (anchors)
|
|
|
|
| 340 |
if not self.fisher and not self.neuron_fisher:
|
| 341 |
return torch.tensor(0.0, device=next(self.model.parameters()).device), {}
|
| 342 |
|
| 343 |
+
# V6.1 — Short-circuit: se TODOS os neurônios do SOM estão filled,
|
| 344 |
+
# a skip mask zera todo o Fisher Kohonen. E se o classic Fisher
|
| 345 |
+
# também foi mascarado para orq_cell.neuron_cache (feito em
|
| 346 |
+
# compute_fisher), resta apenas o classic Fisher dos outros params.
|
| 347 |
+
# Para evitar NaN por instabilidade numérica na topological penalty
|
| 348 |
+
# (sqrt de diferenças de normas), pulamos o topo penalty quando
|
| 349 |
+
# todos os neurônios estão filled — a topologia já está sendo
|
| 350 |
+
# preservada pelo próprio SOM (BMU + vizinhos puxados na direção
|
| 351 |
+
# do input, Gaussian Λ).
|
| 352 |
+
all_filled = all(
|
| 353 |
+
hasattr(oc, "neuron_filled_mask") and bool(oc.neuron_filled_mask.all().item())
|
| 354 |
+
for oc in self.orq_cells.values()
|
| 355 |
+
) if self.orq_cells else False
|
| 356 |
+
if all_filled and self.cfg.skip_som_filled_neurons:
|
| 357 |
+
# SOM cobre tudo — EWC não tem nada a ancorar
|
| 358 |
+
device = next(self.model.parameters()).device
|
| 359 |
+
metrics = {
|
| 360 |
+
"total_pen": 0.0,
|
| 361 |
+
"n_masked_som_neurons": sum(
|
| 362 |
+
int(oc.neuron_filled_mask.sum().item())
|
| 363 |
+
for oc in self.orq_cells.values()
|
| 364 |
+
if hasattr(oc, "neuron_filled_mask")
|
| 365 |
+
),
|
| 366 |
+
"skipped_reason": "all_som_neurons_filled",
|
| 367 |
+
}
|
| 368 |
+
return torch.tensor(0.0, device=device), metrics
|
| 369 |
+
|
| 370 |
device = next(self.model.parameters()).device
|
| 371 |
metrics: Dict[str, float] = {}
|
| 372 |
total_penalty = torch.tensor(0.0, device=device)
|
|
|
|
| 389 |
# 2. Penalidade Kohonen per-neuron
|
| 390 |
kohonen_pen = torch.tensor(0.0, device=device)
|
| 391 |
n_kohonen = 0
|
| 392 |
+
n_masked_total = 0 # V6.1: contador de neurônios skipped (já no SOM)
|
| 393 |
for orq_name, orq_cell in self.orq_cells.items():
|
| 394 |
if orq_name not in self.neuron_fisher or orq_name not in self.neuron_optimal:
|
| 395 |
continue
|
| 396 |
f_n = self.neuron_fisher[orq_name].to(device) # (n_neurons, d_cache)
|
| 397 |
w_star_n = self.neuron_optimal[orq_name].to(device)
|
| 398 |
w_n = orq_cell.neuron_cache # (n_neurons, d_cache)
|
| 399 |
+
# V6.1 — Aplicar fisher_neuron_mask: zero penalty para filled neurons
|
| 400 |
+
keep_mask = self.fisher_neuron_mask.get(orq_name)
|
| 401 |
+
if keep_mask is not None:
|
| 402 |
+
keep_mask_dev = keep_mask.to(device).float()
|
| 403 |
+
f_n_masked = f_n * keep_mask_dev.unsqueeze(-1)
|
| 404 |
+
n_masked_total += int((1 - keep_mask_dev).sum().item())
|
| 405 |
+
else:
|
| 406 |
+
f_n_masked = f_n
|
| 407 |
# Σ_n Σ_i F_{n,i} (w_{n,i} - w*_{n,i})^2
|
| 408 |
+
pen_n = (f_n_masked * (w_n - w_star_n).pow(2)).sum()
|
| 409 |
# Reforço do BMU: se bmu_indices fornecido, multiplica a penalidade
|
| 410 |
# do neurônio BMU por γ_bmu
|
| 411 |
if bmu_indices is not None and len(bmu_indices) > 0:
|
|
|
|
| 417 |
bmu_weight = 1.0 + (self.cfg.bmu_reinforcement_gamma - 1.0) * (
|
| 418 |
bmu_counts / (bmu_counts.sum() + 1e-8)
|
| 419 |
)
|
| 420 |
+
pen_n = (bmu_weight.unsqueeze(-1) * f_n_masked * (w_n - w_star_n).pow(2)).sum()
|
| 421 |
kohonen_pen = kohonen_pen + pen_n
|
| 422 |
n_kohonen += 1
|
| 423 |
if n_kohonen > 0:
|
| 424 |
kohonen_pen = kohonen_pen / max(1, n_kohonen)
|
| 425 |
metrics["kohonen_pen"] = float(kohonen_pen.item())
|
| 426 |
+
metrics["n_masked_som_neurons"] = n_masked_total # V6.1
|
| 427 |
total_penalty = total_penalty + self._adaptive_lambda * kohonen_pen
|
| 428 |
|
| 429 |
# 3. Penalidade topológica (preserva distâncias no grid 4D)
|
|
|
|
| 485 |
# Status / monitoramento
|
| 486 |
# =====================================================================
|
| 487 |
def get_status(self) -> Dict[str, Any]:
|
| 488 |
+
n_masked = sum(int((~m).sum().item()) for m in self.fisher_neuron_mask.values()) if self.fisher_neuron_mask else 0
|
| 489 |
+
n_active = sum(int(m.sum().item()) for m in self.fisher_neuron_mask.values()) if self.fisher_neuron_mask else 0
|
| 490 |
return {
|
| 491 |
"n_tasks": self.n_tasks,
|
| 492 |
"n_classic_params": len(self.fisher),
|
|
|
|
| 497 |
"bmu_reinforcement_gamma": self.cfg.bmu_reinforcement_gamma,
|
| 498 |
"last_task_grad_norm": self._last_task_grad_norm,
|
| 499 |
"last_ewc_grad_norm": self._last_ewc_grad_norm,
|
| 500 |
+
# V6.1 — info sobre skip mask
|
| 501 |
+
"skip_som_filled_neurons": self.cfg.skip_som_filled_neurons,
|
| 502 |
+
"n_active_ewc_neurons": n_active, # EWC atua nestes
|
| 503 |
+
"n_masked_som_neurons": n_masked, # SOM já cobre estes (não duplica)
|
| 504 |
}
|
| 505 |
|
| 506 |
|
|
@@ -0,0 +1,580 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "V6.1",
|
| 3 |
+
"timestamp": "2026-08-07 00:03:59",
|
| 4 |
+
"config": {
|
| 5 |
+
"datasets": [
|
| 6 |
+
"CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
|
| 7 |
+
"Madras1/corpus-ptbr-v2",
|
| 8 |
+
"TucanoBR/GigaVerbo",
|
| 9 |
+
"nvidia/OpenMathInstruct-2",
|
| 10 |
+
"dominguesm/restore-punctuation-ptbr-dataset"
|
| 11 |
+
],
|
| 12 |
+
"n_per_dataset": 10,
|
| 13 |
+
"epochs": 2,
|
| 14 |
+
"batch_size": 4,
|
| 15 |
+
"max_seq_len": 16,
|
| 16 |
+
"num_layers_hyp": 8,
|
| 17 |
+
"use_mtp": true,
|
| 18 |
+
"use_ewc": true,
|
| 19 |
+
"use_kohonen_orq": true,
|
| 20 |
+
"mtp_K": 4,
|
| 21 |
+
"mtp_entropy_beta": 0.01,
|
| 22 |
+
"ewc_lambda": 0.0,
|
| 23 |
+
"ewc_lambda_topo": 0.05,
|
| 24 |
+
"pgv_complete_thr": 0.6,
|
| 25 |
+
"pgv_missing_thr": 0.2
|
| 26 |
+
},
|
| 27 |
+
"v6_1_improvements": {
|
| 28 |
+
"pgvector_like_lookup": {
|
| 29 |
+
"method": "pgvector_lookup() no OrqCell",
|
| 30 |
+
"statuses": [
|
| 31 |
+
"COMPLETE",
|
| 32 |
+
"INCOMPLETE",
|
| 33 |
+
"MISSING"
|
| 34 |
+
],
|
| 35 |
+
"complete_threshold": 0.6,
|
| 36 |
+
"missing_threshold": 0.2,
|
| 37 |
+
"neuron_filled_mask": true,
|
| 38 |
+
"auto_fill_missing": true
|
| 39 |
+
},
|
| 40 |
+
"ewc_math_upgrade": {
|
| 41 |
+
"skip_som_filled_neurons": true,
|
| 42 |
+
"rationale": "EWC n\u00e3o reutiliza pesos j\u00e1 presentes no SOM \u2014 evita dupla penaliza\u00e7\u00e3o (BMU + Fisher)",
|
| 43 |
+
"fisher_neuron_mask": true,
|
| 44 |
+
"n_masked_som_neurons_final": 8
|
| 45 |
+
},
|
| 46 |
+
"5_datasets_x_10_samples": true,
|
| 47 |
+
"hypothesis_level_pgvector": true,
|
| 48 |
+
"training_level_pgvector": true
|
| 49 |
+
},
|
| 50 |
+
"v6_features_preserved": {
|
| 51 |
+
"kohonen_4d_som": true,
|
| 52 |
+
"ewc_per_neuron": true,
|
| 53 |
+
"mtp_active_in_val": true,
|
| 54 |
+
"mtp_entropy_regularizer": true,
|
| 55 |
+
"window_context_2m": true,
|
| 56 |
+
"dynamic_rep_penalty": true,
|
| 57 |
+
"data_augmentation": true,
|
| 58 |
+
"rlhf_mapping": true,
|
| 59 |
+
"thinking_system": true,
|
| 60 |
+
"tool_system": [
|
| 61 |
+
"mutation",
|
| 62 |
+
"cache",
|
| 63 |
+
"agent"
|
| 64 |
+
],
|
| 65 |
+
"langchain_compat": true,
|
| 66 |
+
"optimized_pipeline": true,
|
| 67 |
+
"xeon_v6_always_active": true,
|
| 68 |
+
"libvirt_amx_vm_activation": true
|
| 69 |
+
},
|
| 70 |
+
"xeon_status": {
|
| 71 |
+
"version": "V6",
|
| 72 |
+
"physical_cores": 2,
|
| 73 |
+
"env": {
|
| 74 |
+
"MKL_ENABLE_INSTRUCTIONS": "AVX512",
|
| 75 |
+
"MKL_NUM_THREADS": "2",
|
| 76 |
+
"OMP_NUM_THREADS": "2",
|
| 77 |
+
"MKL_DYNAMIC": "FALSE",
|
| 78 |
+
"DNNL_PRIMITIVE_CACHE_CAPACITY": "1024",
|
| 79 |
+
"ONEDNN_MAX_CPU_ISA": "AMX_INT8",
|
| 80 |
+
"KMP_AFFINITY": "granularity=fine,compact,1,0",
|
| 81 |
+
"KMP_BLOCKTIME": "1"
|
| 82 |
+
},
|
| 83 |
+
"avx512": {
|
| 84 |
+
"supported": true,
|
| 85 |
+
"desc": "AVX512_VNNI (full INT8 acceleration)"
|
| 86 |
+
},
|
| 87 |
+
"amx": {
|
| 88 |
+
"supported": true,
|
| 89 |
+
"desc": "AMX (tile + int8 + bf16) \u2014 full AMX acceleration"
|
| 90 |
+
},
|
| 91 |
+
"ipex_available": false,
|
| 92 |
+
"init_done": true
|
| 93 |
+
},
|
| 94 |
+
"fp16_benchmark": {
|
| 95 |
+
"best_time_ms": 8.137860999795521,
|
| 96 |
+
"avg_time_ms": 9.180876000073113,
|
| 97 |
+
"best_tflops": 1.966118615248163,
|
| 98 |
+
"avg_tflops": 1.7427530880356714,
|
| 99 |
+
"matrix_size": 2000.0
|
| 100 |
+
},
|
| 101 |
+
"dataset_distribution": {
|
| 102 |
+
"CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": 6,
|
| 103 |
+
"Madras1/corpus-ptbr-v2": 4,
|
| 104 |
+
"TucanoBR/GigaVerbo": 6,
|
| 105 |
+
"nvidia/OpenMathInstruct-2": 4
|
| 106 |
+
},
|
| 107 |
+
"result": {
|
| 108 |
+
"n_steps": 20,
|
| 109 |
+
"n_epochs": 2,
|
| 110 |
+
"final_train_loss": 8.95526123046875,
|
| 111 |
+
"final_val_loss": 9.007498455047607,
|
| 112 |
+
"final_perplexity": 8164.072913971902,
|
| 113 |
+
"final_overfitting_gap": 0.5984001159667969,
|
| 114 |
+
"final_eval_benchmark": 0.0,
|
| 115 |
+
"avg_tokens_per_sec": 34.57634302712832,
|
| 116 |
+
"avg_tflops_per_cpu": 0.000667780381373023,
|
| 117 |
+
"avg_time_per_step_ms": 1852.609849800024,
|
| 118 |
+
"avg_grad_norm": 9.19138070344925,
|
| 119 |
+
"avg_cpu_pct": 137.995,
|
| 120 |
+
"final_rss_mb": 872.390625,
|
| 121 |
+
"max_rss_mb": 880.421875,
|
| 122 |
+
"rss_trend": "stable",
|
| 123 |
+
"n_alerts": 0,
|
| 124 |
+
"alerts": [],
|
| 125 |
+
"alert_types": [],
|
| 126 |
+
"meta_history": [],
|
| 127 |
+
"kohonen_evolution": {
|
| 128 |
+
"sigma_t": [
|
| 129 |
+
1.384021282196045,
|
| 130 |
+
1.2770098447799683,
|
| 131 |
+
1.1782726049423218,
|
| 132 |
+
1.0871695280075073,
|
| 133 |
+
1.003110408782959,
|
| 134 |
+
0.9255508184432983,
|
| 135 |
+
0.853987991809845,
|
| 136 |
+
0.7879583239555359,
|
| 137 |
+
0.7270340323448181,
|
| 138 |
+
0.670820415019989,
|
| 139 |
+
0.6189531087875366,
|
| 140 |
+
0.5710961818695068,
|
| 141 |
+
0.5269395112991333,
|
| 142 |
+
0.48619696497917175,
|
| 143 |
+
0.44860464334487915,
|
| 144 |
+
0.4139189124107361,
|
| 145 |
+
0.38191503286361694,
|
| 146 |
+
0.35238566994667053,
|
| 147 |
+
0.32513952255249023,
|
| 148 |
+
0.30000001192092896
|
| 149 |
+
],
|
| 150 |
+
"alpha_t": [
|
| 151 |
+
0.4456254541873932,
|
| 152 |
+
0.39716410636901855,
|
| 153 |
+
0.3539728820323944,
|
| 154 |
+
0.31547868251800537,
|
| 155 |
+
0.28117066621780396,
|
| 156 |
+
0.2505936026573181,
|
| 157 |
+
0.22334179282188416,
|
| 158 |
+
0.1990535855293274,
|
| 159 |
+
0.1774066984653473,
|
| 160 |
+
0.15811388194561005,
|
| 161 |
+
0.14091914892196655,
|
| 162 |
+
0.12559431791305542,
|
| 163 |
+
0.111936055123806,
|
| 164 |
+
0.09976311773061752,
|
| 165 |
+
0.08891396969556808,
|
| 166 |
+
0.07924465835094452,
|
| 167 |
+
0.0706268772482872,
|
| 168 |
+
0.06294626742601395,
|
| 169 |
+
0.05610092356801033,
|
| 170 |
+
0.05000000074505806
|
| 171 |
+
],
|
| 172 |
+
"bmu_diversity": [
|
| 173 |
+
1,
|
| 174 |
+
1,
|
| 175 |
+
1,
|
| 176 |
+
2,
|
| 177 |
+
2,
|
| 178 |
+
1,
|
| 179 |
+
1,
|
| 180 |
+
1,
|
| 181 |
+
1,
|
| 182 |
+
1,
|
| 183 |
+
1,
|
| 184 |
+
1,
|
| 185 |
+
1,
|
| 186 |
+
1,
|
| 187 |
+
1,
|
| 188 |
+
1,
|
| 189 |
+
1,
|
| 190 |
+
1,
|
| 191 |
+
1,
|
| 192 |
+
1
|
| 193 |
+
],
|
| 194 |
+
"map_entropy": [
|
| 195 |
+
-0.0,
|
| 196 |
+
-0.0,
|
| 197 |
+
-0.0,
|
| 198 |
+
0.5623351335525513,
|
| 199 |
+
0.5623351335525513,
|
| 200 |
+
-0.0,
|
| 201 |
+
-0.0,
|
| 202 |
+
-0.0,
|
| 203 |
+
-0.0,
|
| 204 |
+
-0.0,
|
| 205 |
+
-0.0,
|
| 206 |
+
-0.0,
|
| 207 |
+
-0.0,
|
| 208 |
+
-0.0,
|
| 209 |
+
-0.0,
|
| 210 |
+
-0.0,
|
| 211 |
+
-0.0,
|
| 212 |
+
-0.0,
|
| 213 |
+
-0.0,
|
| 214 |
+
-0.0
|
| 215 |
+
],
|
| 216 |
+
"neighborhood_spread": [
|
| 217 |
+
0.69346022605896,
|
| 218 |
+
0.6539043188095093,
|
| 219 |
+
0.6115002036094666,
|
| 220 |
+
0.5666936039924622,
|
| 221 |
+
0.5201174020767212,
|
| 222 |
+
0.4725886881351471,
|
| 223 |
+
0.4250819981098175,
|
| 224 |
+
0.37867772579193115,
|
| 225 |
+
0.33448442816734314,
|
| 226 |
+
0.2935446500778198,
|
| 227 |
+
0.25673601031303406,
|
| 228 |
+
0.22468914091587067,
|
| 229 |
+
0.19773666560649872,
|
| 230 |
+
0.17590436339378357,
|
| 231 |
+
0.15894067287445068,
|
| 232 |
+
0.14637233316898346,
|
| 233 |
+
0.13756908476352692,
|
| 234 |
+
0.13180842995643616,
|
| 235 |
+
0.12834037840366364,
|
| 236 |
+
0.12645532190799713
|
| 237 |
+
],
|
| 238 |
+
"update_magnitude": [
|
| 239 |
+
1.7733118534088135,
|
| 240 |
+
1.1040481328964233,
|
| 241 |
+
0.7362503409385681,
|
| 242 |
+
0.5203624963760376,
|
| 243 |
+
0.3804885745048523,
|
| 244 |
+
0.28771743178367615,
|
| 245 |
+
0.21806250512599945,
|
| 246 |
+
0.1706063151359558,
|
| 247 |
+
0.13349632918834686,
|
| 248 |
+
0.10120385140180588,
|
| 249 |
+
0.07817182689905167,
|
| 250 |
+
0.0603366494178772,
|
| 251 |
+
0.045329220592975616,
|
| 252 |
+
0.03576458618044853,
|
| 253 |
+
0.028652094304561615,
|
| 254 |
+
0.02487526461482048,
|
| 255 |
+
0.020203959196805954,
|
| 256 |
+
0.017652250826358795,
|
| 257 |
+
0.017456991598010063,
|
| 258 |
+
0.017063762992620468
|
| 259 |
+
],
|
| 260 |
+
"bmu_drift": [
|
| 261 |
+
0.24679547548294067,
|
| 262 |
+
0.3537101149559021,
|
| 263 |
+
0.23110663890838623,
|
| 264 |
+
0.14959216117858887,
|
| 265 |
+
0.09846150875091553,
|
| 266 |
+
0.06671786308288574,
|
| 267 |
+
0.04513096809387207,
|
| 268 |
+
0.031584978103637695,
|
| 269 |
+
0.021926403045654297,
|
| 270 |
+
0.014822602272033691,
|
| 271 |
+
0.010076165199279785,
|
| 272 |
+
0.006844878196716309,
|
| 273 |
+
0.004448533058166504,
|
| 274 |
+
0.0029137134552001953,
|
| 275 |
+
0.0018589496612548828,
|
| 276 |
+
0.0012536048889160156,
|
| 277 |
+
0.0007802248001098633,
|
| 278 |
+
0.000525355339050293,
|
| 279 |
+
0.00039505958557128906,
|
| 280 |
+
0.0002874135971069336
|
| 281 |
+
],
|
| 282 |
+
"n_filled": [
|
| 283 |
+
8,
|
| 284 |
+
8,
|
| 285 |
+
8,
|
| 286 |
+
8,
|
| 287 |
+
8,
|
| 288 |
+
8,
|
| 289 |
+
8,
|
| 290 |
+
8,
|
| 291 |
+
8,
|
| 292 |
+
8,
|
| 293 |
+
8,
|
| 294 |
+
8,
|
| 295 |
+
8,
|
| 296 |
+
8,
|
| 297 |
+
8,
|
| 298 |
+
8,
|
| 299 |
+
8,
|
| 300 |
+
8,
|
| 301 |
+
8,
|
| 302 |
+
8
|
| 303 |
+
],
|
| 304 |
+
"filled_ratio": [
|
| 305 |
+
1.0,
|
| 306 |
+
1.0,
|
| 307 |
+
1.0,
|
| 308 |
+
1.0,
|
| 309 |
+
1.0,
|
| 310 |
+
1.0,
|
| 311 |
+
1.0,
|
| 312 |
+
1.0,
|
| 313 |
+
1.0,
|
| 314 |
+
1.0,
|
| 315 |
+
1.0,
|
| 316 |
+
1.0,
|
| 317 |
+
1.0,
|
| 318 |
+
1.0,
|
| 319 |
+
1.0,
|
| 320 |
+
1.0,
|
| 321 |
+
1.0,
|
| 322 |
+
1.0,
|
| 323 |
+
1.0,
|
| 324 |
+
1.0
|
| 325 |
+
],
|
| 326 |
+
"final_sigma_t": 0.30000001192092896,
|
| 327 |
+
"final_alpha_t": 0.05000000074505806,
|
| 328 |
+
"sigma_decay": 1.084021270275116,
|
| 329 |
+
"alpha_decay": 0.39562545344233513,
|
| 330 |
+
"final_n_filled": 8,
|
| 331 |
+
"final_filled_ratio": 1.0
|
| 332 |
+
},
|
| 333 |
+
"mtp_evolution": {
|
| 334 |
+
"train_loss": [
|
| 335 |
+
6.553211212158203,
|
| 336 |
+
6.4814019203186035,
|
| 337 |
+
6.512597560882568,
|
| 338 |
+
6.508908748626709,
|
| 339 |
+
6.495436191558838,
|
| 340 |
+
6.468592643737793,
|
| 341 |
+
6.456118583679199,
|
| 342 |
+
6.389763355255127,
|
| 343 |
+
6.352229118347168,
|
| 344 |
+
6.327796459197998,
|
| 345 |
+
6.411394119262695,
|
| 346 |
+
6.3602471351623535,
|
| 347 |
+
6.394613265991211,
|
| 348 |
+
6.356604099273682,
|
| 349 |
+
6.3215155601501465,
|
| 350 |
+
6.312246799468994,
|
| 351 |
+
6.3158793449401855,
|
| 352 |
+
6.214627265930176,
|
| 353 |
+
6.1928935050964355,
|
| 354 |
+
6.155653953552246
|
| 355 |
+
],
|
| 356 |
+
"val_loss": [
|
| 357 |
+
6.393180084228516,
|
| 358 |
+
6.224726915359497
|
| 359 |
+
],
|
| 360 |
+
"entropy_reg": [
|
| 361 |
+
1.3862943649291992,
|
| 362 |
+
1.3862943649291992,
|
| 363 |
+
1.3862941265106201,
|
| 364 |
+
1.3862940073013306,
|
| 365 |
+
1.3862937688827515,
|
| 366 |
+
1.3862934112548828,
|
| 367 |
+
1.3862931728363037,
|
| 368 |
+
1.3862926959991455,
|
| 369 |
+
1.3862920999526978,
|
| 370 |
+
1.38629150390625,
|
| 371 |
+
1.3862910270690918,
|
| 372 |
+
1.3862903118133545,
|
| 373 |
+
1.3862894773483276,
|
| 374 |
+
1.3862886428833008,
|
| 375 |
+
1.3862876892089844,
|
| 376 |
+
1.386286735534668,
|
| 377 |
+
1.386285662651062,
|
| 378 |
+
1.386284589767456,
|
| 379 |
+
1.3862833976745605,
|
| 380 |
+
1.3862820863723755
|
| 381 |
+
],
|
| 382 |
+
"final_alphas": [
|
| 383 |
+
0.24928787350654602,
|
| 384 |
+
0.24928365647792816,
|
| 385 |
+
0.2492905557155609,
|
| 386 |
+
0.2521378993988037
|
| 387 |
+
]
|
| 388 |
+
},
|
| 389 |
+
"ewc_evolution": {
|
| 390 |
+
"total_penalty": [
|
| 391 |
+
0.0,
|
| 392 |
+
0.0,
|
| 393 |
+
0.0,
|
| 394 |
+
0.0,
|
| 395 |
+
0.0,
|
| 396 |
+
0.0,
|
| 397 |
+
0.0,
|
| 398 |
+
0.0,
|
| 399 |
+
0.0,
|
| 400 |
+
0.0
|
| 401 |
+
],
|
| 402 |
+
"classic_pen": [
|
| 403 |
+
0,
|
| 404 |
+
0,
|
| 405 |
+
0,
|
| 406 |
+
0,
|
| 407 |
+
0,
|
| 408 |
+
0,
|
| 409 |
+
0,
|
| 410 |
+
0,
|
| 411 |
+
0,
|
| 412 |
+
0
|
| 413 |
+
],
|
| 414 |
+
"kohonen_pen": [
|
| 415 |
+
0,
|
| 416 |
+
0,
|
| 417 |
+
0,
|
| 418 |
+
0,
|
| 419 |
+
0,
|
| 420 |
+
0,
|
| 421 |
+
0,
|
| 422 |
+
0,
|
| 423 |
+
0,
|
| 424 |
+
0
|
| 425 |
+
],
|
| 426 |
+
"topo_pen": [
|
| 427 |
+
0,
|
| 428 |
+
0,
|
| 429 |
+
0,
|
| 430 |
+
0,
|
| 431 |
+
0,
|
| 432 |
+
0,
|
| 433 |
+
0,
|
| 434 |
+
0,
|
| 435 |
+
0,
|
| 436 |
+
0
|
| 437 |
+
],
|
| 438 |
+
"n_masked_som_neurons": [
|
| 439 |
+
8,
|
| 440 |
+
8,
|
| 441 |
+
8,
|
| 442 |
+
8,
|
| 443 |
+
8,
|
| 444 |
+
8,
|
| 445 |
+
8,
|
| 446 |
+
8,
|
| 447 |
+
8,
|
| 448 |
+
8
|
| 449 |
+
]
|
| 450 |
+
},
|
| 451 |
+
"pgvector_evolution": {
|
| 452 |
+
"status_per_step": [
|
| 453 |
+
"MISSING",
|
| 454 |
+
"INCOMPLETE",
|
| 455 |
+
"INCOMPLETE",
|
| 456 |
+
"INCOMPLETE",
|
| 457 |
+
"INCOMPLETE",
|
| 458 |
+
"INCOMPLETE",
|
| 459 |
+
"INCOMPLETE",
|
| 460 |
+
"INCOMPLETE",
|
| 461 |
+
"INCOMPLETE",
|
| 462 |
+
"INCOMPLETE",
|
| 463 |
+
"INCOMPLETE",
|
| 464 |
+
"INCOMPLETE",
|
| 465 |
+
"INCOMPLETE",
|
| 466 |
+
"INCOMPLETE",
|
| 467 |
+
"INCOMPLETE",
|
| 468 |
+
"INCOMPLETE",
|
| 469 |
+
"INCOMPLETE",
|
| 470 |
+
"INCOMPLETE",
|
| 471 |
+
"INCOMPLETE",
|
| 472 |
+
"INCOMPLETE"
|
| 473 |
+
],
|
| 474 |
+
"status_counts": {
|
| 475 |
+
"COMPLETE": 0,
|
| 476 |
+
"INCOMPLETE": 19,
|
| 477 |
+
"MISSING": 1
|
| 478 |
+
},
|
| 479 |
+
"coverage_ratio": [
|
| 480 |
+
0.0,
|
| 481 |
+
1.0,
|
| 482 |
+
1.0,
|
| 483 |
+
1.0,
|
| 484 |
+
1.0,
|
| 485 |
+
1.0,
|
| 486 |
+
1.0,
|
| 487 |
+
1.0,
|
| 488 |
+
1.0,
|
| 489 |
+
1.0,
|
| 490 |
+
1.0,
|
| 491 |
+
1.0,
|
| 492 |
+
1.0,
|
| 493 |
+
1.0,
|
| 494 |
+
1.0,
|
| 495 |
+
1.0,
|
| 496 |
+
1.0,
|
| 497 |
+
1.0,
|
| 498 |
+
1.0,
|
| 499 |
+
1.0
|
| 500 |
+
],
|
| 501 |
+
"best_sim": [
|
| 502 |
+
0.14598573744297028,
|
| 503 |
+
0.40406447649002075,
|
| 504 |
+
0.418964684009552,
|
| 505 |
+
0.40291208028793335,
|
| 506 |
+
0.3913118839263916,
|
| 507 |
+
0.3694383203983307,
|
| 508 |
+
0.3722689151763916,
|
| 509 |
+
0.3724372982978821,
|
| 510 |
+
0.3629907965660095,
|
| 511 |
+
0.35789668560028076,
|
| 512 |
+
0.3523437976837158,
|
| 513 |
+
0.34320616722106934,
|
| 514 |
+
0.33242273330688477,
|
| 515 |
+
0.3401498794555664,
|
| 516 |
+
0.3416547179222107,
|
| 517 |
+
0.31360486149787903,
|
| 518 |
+
0.3154335618019104,
|
| 519 |
+
0.3324233889579773,
|
| 520 |
+
0.3183605372905731,
|
| 521 |
+
0.324212908744812
|
| 522 |
+
],
|
| 523 |
+
"n_filled": [
|
| 524 |
+
0,
|
| 525 |
+
8,
|
| 526 |
+
8,
|
| 527 |
+
8,
|
| 528 |
+
8,
|
| 529 |
+
8,
|
| 530 |
+
8,
|
| 531 |
+
8,
|
| 532 |
+
8,
|
| 533 |
+
8,
|
| 534 |
+
8,
|
| 535 |
+
8,
|
| 536 |
+
8,
|
| 537 |
+
8,
|
| 538 |
+
8,
|
| 539 |
+
8,
|
| 540 |
+
8,
|
| 541 |
+
8,
|
| 542 |
+
8,
|
| 543 |
+
8
|
| 544 |
+
],
|
| 545 |
+
"filled_ratio": [
|
| 546 |
+
0.0,
|
| 547 |
+
1.0,
|
| 548 |
+
1.0,
|
| 549 |
+
1.0,
|
| 550 |
+
1.0,
|
| 551 |
+
1.0,
|
| 552 |
+
1.0,
|
| 553 |
+
1.0,
|
| 554 |
+
1.0,
|
| 555 |
+
1.0,
|
| 556 |
+
1.0,
|
| 557 |
+
1.0,
|
| 558 |
+
1.0,
|
| 559 |
+
1.0,
|
| 560 |
+
1.0,
|
| 561 |
+
1.0,
|
| 562 |
+
1.0,
|
| 563 |
+
1.0,
|
| 564 |
+
1.0,
|
| 565 |
+
1.0
|
| 566 |
+
],
|
| 567 |
+
"final_coverage": 1.0,
|
| 568 |
+
"final_best_sim": 0.324212908744812,
|
| 569 |
+
"final_n_filled": 8,
|
| 570 |
+
"final_filled_ratio": 1.0
|
| 571 |
+
},
|
| 572 |
+
"dataset_distribution": {
|
| 573 |
+
"CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": 6,
|
| 574 |
+
"Madras1/corpus-ptbr-v2": 4,
|
| 575 |
+
"TucanoBR/GigaVerbo": 6,
|
| 576 |
+
"nvidia/OpenMathInstruct-2": 4
|
| 577 |
+
},
|
| 578 |
+
"n_params_M": 9.656608
|
| 579 |
+
}
|
| 580 |
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "V6",
|
| 3 |
+
"timestamp": "2026-08-06 23:32:19",
|
| 4 |
+
"repo_id": "PowerMachine/BiGRU_T_version",
|
| 5 |
+
"commit_url": "https://huggingface.co/PowerMachine/BiGRU_T_version/commit/79e8e52633961c9ff5652034b9f781ff66416ed8",
|
| 6 |
+
"elapsed_seconds": 3.12007878899999,
|
| 7 |
+
"n_files_uploaded": 88,
|
| 8 |
+
"n_files_in_repo_before": 0,
|
| 9 |
+
"n_files_in_repo_after": 0,
|
| 10 |
+
"new_files": [],
|
| 11 |
+
"critical_files_ok": false,
|
| 12 |
+
"critical_files": [
|
| 13 |
+
"src/bigru_t/model/orq_cell.py",
|
| 14 |
+
"src/bigru_t/training/ewc.py",
|
| 15 |
+
"src/bigru_t/training/mtp.py",
|
| 16 |
+
"src/bigru_t/training/dynamic_repetition_penalty.py",
|
| 17 |
+
"src/bigru_t/training/data_augmentation.py",
|
| 18 |
+
"src/bigru_t/training/rlhf_mapping.py",
|
| 19 |
+
"src/bigru_t/attention/window_context.py",
|
| 20 |
+
"src/bigru_t/reasoning/thinking.py",
|
| 21 |
+
"src/bigru_t/tools/tool_mutation.py",
|
| 22 |
+
"src/bigru_t/tools/tool_cache.py",
|
| 23 |
+
"src/bigru_t/tools/tool_agent.py",
|
| 24 |
+
"src/bigru_t/integrations/langchain_compat.py",
|
| 25 |
+
"src/bigru_t/pipeline/optimized_pipeline.py",
|
| 26 |
+
"src/bigru_t/utils/xeon_runtime.py",
|
| 27 |
+
"v6_report.json"
|
| 28 |
+
]
|
| 29 |
+
}
|