PowerMachine commited on
Commit
81ff26f
·
verified ·
1 Parent(s): 7972ba8

V6.5-V2-unified: cleanup misplaced root files + old scripts [18 files deleted] — removes duplicates from repo root (they live in src/bigru_t/...) and outdated scripts in scripts/ (now in deprecados/)

Browse files
attention_multimodal.py DELETED
@@ -1,114 +0,0 @@
1
- """
2
- Xavante - attention_multimodal.py
3
- Responsabilidade: Multi-head attention multimodal (Teorema 11.1/11.2).
4
- Suporta attention entre modalidades e dentro de modalidade.
5
- """
6
- from __future__ import annotations
7
-
8
- import logging
9
- import math
10
- from typing import Optional
11
-
12
- import torch
13
- import torch.nn as nn
14
- import torch.nn.functional as F
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- class MultiHeadAttention(nn.Module):
20
- """
21
- MHA padrão com suporte a:
22
- - Mascara causal
23
- - Mascara multimodal (mod crossing)
24
- - Attention 2M tokens via chunked attention (Teorema 6.1)
25
- """
26
-
27
- def __init__(
28
- self,
29
- d_model: int,
30
- n_heads: int = 8,
31
- dropout: float = 0.0,
32
- max_chunk: int = 4096,
33
- ):
34
- super().__init__()
35
- assert d_model % n_heads == 0
36
- self.d_model = d_model
37
- self.n_heads = n_heads
38
- self.d_head = d_model // n_heads
39
- self.max_chunk = max_chunk
40
- self.qkv = nn.Linear(d_model, 3 * d_model, bias=True)
41
- self.out = nn.Linear(d_model, d_model)
42
- self.dropout = nn.Dropout(dropout)
43
-
44
- def forward(
45
- self,
46
- x: torch.Tensor,
47
- mask: Optional[torch.Tensor] = None,
48
- kv: Optional[torch.Tensor] = None,
49
- ) -> torch.Tensor:
50
- B, L, D = x.shape
51
- if kv is None:
52
- qkv = self.qkv(x)
53
- q, k, v = qkv.chunk(3, dim=-1)
54
- else:
55
- q = self.qkv(x)[:, :, :D]
56
- kv_proj = self.qkv(kv)
57
- k = kv_proj[:, :, D : 2 * D]
58
- v = kv_proj[:, :, 2 * D :]
59
- # reshape para heads
60
- q = q.view(B, L, self.n_heads, self.d_head).transpose(1, 2)
61
- k = k.view(B, -1, self.n_heads, self.d_head).transpose(1, 2)
62
- v = v.view(B, -1, self.n_heads, self.d_head).transpose(1, 2)
63
-
64
- # Chunked attention para sequencias longas (Teorema 6.1)
65
- if L > self.max_chunk:
66
- # Normalize mask to 4D for chunked path
67
- if mask is not None and mask.dim() == 2:
68
- mask = mask.unsqueeze(0).unsqueeze(0)
69
- elif mask is not None and mask.dim() == 3:
70
- mask = mask.unsqueeze(1)
71
- return self._chunked_attention(q, k, v, mask)
72
-
73
- scale = 1.0 / math.sqrt(self.d_head)
74
- attn = (q @ k.transpose(-2, -1)) * scale # [B, H, L, L]
75
- if mask is not None:
76
- attn = attn.masked_fill(mask == 0, float("-inf"))
77
- attn = F.softmax(attn, dim=-1)
78
- attn = self.dropout(attn)
79
- out = attn @ v # [B, H, L, d_head]
80
- out = out.transpose(1, 2).contiguous().view(B, L, D)
81
- return self.out(out)
82
-
83
- def _chunked_attention(
84
- self,
85
- q: torch.Tensor,
86
- k: torch.Tensor,
87
- v: torch.Tensor,
88
- mask: Optional[torch.Tensor],
89
- ) -> torch.Tensor:
90
- """Attention em blocos para janelas de 2M tokens (memoria controlada)."""
91
- B, H, L, d = q.shape
92
- Lk = k.shape[2]
93
- chunk = self.max_chunk
94
- outs = []
95
- scale = 1.0 / math.sqrt(d)
96
- for i in range(0, L, chunk):
97
- qi = q[:, :, i : i + chunk]
98
- out_chunk = []
99
- for j in range(0, Lk, chunk):
100
- kj = k[:, :, j : j + chunk]
101
- vj = v[:, :, j : j + chunk]
102
- attn = (qi @ kj.transpose(-2, -1)) * scale
103
- if mask is not None:
104
- m_chunk = mask[:, :, i : i + chunk, j : j + chunk]
105
- attn = attn.masked_fill(m_chunk == 0, float("-inf"))
106
- attn = F.softmax(attn, dim=-1)
107
- out_chunk.append(attn @ vj)
108
- outs.append(torch.cat(out_chunk, dim=2))
109
- out = torch.cat(outs, dim=2)
110
- out = out.transpose(1, 2).contiguous().view(B, L, self.n_heads * d)
111
- return self.out(out)
112
-
113
-
114
- __all__ = ["MultiHeadAttention"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
hyp_t.py DELETED
@@ -1,100 +0,0 @@
1
- """hyp_t.py — HypT: cabeça de hipótese (correção delta). Implementa o Lema 3.
2
-
3
- A Hipótese é treinada para cancelar o ruído de quantização W8A8:
4
- y_final = y_hat + delta
5
- onde delta = hyp_T(o).
6
-
7
- Diferenças vs. TrainT:
8
- - Recebe `o` opcionalmente destacado (stop_grad) para isolar o sinal de
9
- correção do gradiente principal
10
- - Mesma arquitetura (TransformerEncoder) — apenas o tratamento de gradiente
11
- difere
12
-
13
- Reaproveita a filosofia do HypothesisNetwork do v13.9.2 (16 hipóteses com
14
- mapeamento LoRA), mas simplificada: 1 única hipótese global (delta) em vez
15
- de 16 hipóteses paralelas. A multiplexação é feita pelo OrqCell + Lema 1.
16
-
17
- ============================================================================
18
- V6.4 — pgvector_lookup REMOVIDO (NÃO É MAIS NECESSÁRIO)
19
- ============================================================================
20
- Conforme directive do usuário:
21
- "pgvector_lookup não é mais necessário pela lógica do script seguinte"
22
-
23
- O KohonenLearningSystem (kohonen_refactored/kohonen_learning_system.py)
24
- contém o método find_bmu que realiza busca nearest-neighbor sobre o grid
25
- 4D do SOM (864 neurônios para grid (6,6,6,4)), substituindo qualquer
26
- lookup pgvector externo. A decisão de aplicar punição é delegada ao
27
- protocolo interno do KohonenLearningSystem (1ª punição → activate_hypothesis,
28
- 2ª punição → set_ewc_reference + reset).
29
-
30
- Consequentemente, HypT volta ao seu papel original: gerar a correção
31
- delta = hyp_T(o) sem consultar mapa externo. A integração com o SOM é
32
- feita no nível do trainer (KohonenLearningSystem.process_batch), não no
33
- nível da hipótese.
34
-
35
- Os contadores de punição (n_complete_skip, n_incomplete_apply, etc.)
36
- foram removidos pois não há mais decisão de skip baseada em pgvector.
37
- """
38
- from __future__ import annotations
39
-
40
- import torch
41
- import torch.nn as nn
42
-
43
-
44
- class HypT(nn.Module):
45
- """Transformer de hipótese: gera correção delta.
46
-
47
- Args:
48
- d_input: dimensão de entrada (saída do OrqCell = d_cache)
49
- d_model: dimensão interna
50
- nhead: nº de cabeças
51
- d_ff: dimensão do FFN
52
- output_dim: dimensão de saída (igual ao TrainT)
53
- num_layers: nº de camadas
54
- dropout: probabilidade de dropout
55
-
56
- Forward:
57
- o: (batch, d_input), stop_grad: bool → delta: (batch, output_dim)
58
-
59
- Se stop_grad=True, aplica o.detach() no início — Lema 3 (isolar correção
60
- do gradiente principal).
61
- """
62
-
63
- def __init__(
64
- self,
65
- d_input: int,
66
- d_model: int,
67
- nhead: int,
68
- d_ff: int,
69
- output_dim: int,
70
- num_layers: int = 2,
71
- dropout: float = 0.1,
72
- ):
73
- super().__init__()
74
- self.d_input = d_input
75
- self.d_model = d_model
76
- self.output_dim = output_dim
77
-
78
- self.proj_in = nn.Linear(d_input, d_model)
79
- encoder_layer = nn.TransformerEncoderLayer(
80
- d_model, nhead, d_ff, dropout=dropout, batch_first=True
81
- )
82
- self.encoder = nn.TransformerEncoder(encoder_layer, num_layers)
83
- self.proj_out = nn.Linear(d_model, output_dim)
84
-
85
- def forward(self, o: torch.Tensor, stop_grad: bool = True) -> torch.Tensor:
86
- """o: (batch, d_input) → delta: (batch, output_dim)
87
-
88
- V6.4: SEM consulta pgvector — delta é computado diretamente.
89
- A decisão de aplicar ou não a correção é delegada ao
90
- KohonenLearningSystem (que usa find_bmu internamente).
91
- """
92
- # Lema 3: stop_grad_hyp isola o sinal de correção
93
- if stop_grad:
94
- o = o.detach()
95
-
96
- x = o.unsqueeze(1) # (batch, 1, d_input)
97
- x = self.proj_in(x) # (batch, 1, d_model)
98
- x = self.encoder(x) # (batch, 1, d_model)
99
- delta = self.proj_out(x.squeeze(1)) # (batch, output_dim)
100
- return delta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
kohonen_learning_system.py DELETED
The diff for this file is too large to render. See raw diff
 
scripts/train_v6_4.py DELETED
@@ -1,600 +0,0 @@
1
- """train_v6_4.py — V6.4 REFACTORED Kohonen Learning System (pgvector_lookup REMOVED).
2
-
3
- ═══════════════════════════════════════════════════════════════════════════════
4
- V6.4 — REFATORAÇÃO CANÔNICA COM CÓDIGO FORNECIDO PELO USUÁRIO
5
- ═══════════════════════════════════════════════════════════════════════════════
6
-
7
- Refatoração sobrescreve os módulos usando o código Kohonen SOM 4D fornecido
8
- pelo usuário (versão limpa, find_bmu já corrigido). Análise matemática
9
- formal documentada em kohonen_learning_system.py.
10
-
11
- Diferenças vs V6.3:
12
- 1. pgvector_lookup REMOVIDO de hyp_t.py (não é mais necessário —
13
- find_bmu do KohonenLearningSystem realiza a busca nearest-neighbor
14
- sobre o grid 4D, substituindo qualquer lookup pgvector externo).
15
- 2. SOM grid放大ado para (6,6,6,4) = 864 neurônios (default do usuário).
16
- 3. hidden_dim=1024 (default do usuário, era 256 no V6.3).
17
- 4. T_max=10000 (default do usuário).
18
- 5. w = time_step / T_max (LINEAR no tempo, era sigmoid(||xyz||) no V6.3).
19
- 6. API unificada: kls.som.get_metrics() e kls.get_state_metrics().
20
-
21
- Componentes ativados:
22
- 1. xeon_runtime.py (AVX512 + AMX_INT8 + IPEX + OneDNN + FP16)
23
- 2. streaming_datasets.py (5 datasets × 50 samples = 250 total)
24
- 3. KohonenLearningSystem (refatorado, código CANÔNICO do usuário)
25
- 4. BATCH_SIZE = 16 (user requirement)
26
- 5. Captura de métricas: 12/12 + Kohonen (sigma, alpha, fisher) + Hyp
27
- 6. Monitoramento e informe de valores obtidos
28
-
29
- User requirements (V6.4):
30
- - "refatorar sobrescrevendo os módulos usando (analisar matematicamente)"
31
- - "pgvector_lookup não é mais necessário pela lógica do script seguinte"
32
- - "HF_TOKEN=hf_<REDACTED_TOKEN> que deve ser apagada após uso"
33
- - "usar streaming_datasets.py"
34
- - "ativar xeon_runtime.py"
35
- - "BATCH_SIZE = 16"
36
- - "5 datasets × 50 samples streaming"
37
- - "monitorar e informar valores obtidos"
38
-
39
- Saídas:
40
- - /home/z/my-project/BiGRU_T_version/v6_4_report.json
41
- - /home/z/my-project/BiGRU_T_version/v6_4_training_metrics.json
42
- - Log no worklog.md
43
- ═══════════════════════════════════════════════════════════════════════════════
44
- """
45
- from __future__ import annotations
46
-
47
- import json
48
- import logging
49
- import os
50
- import sys
51
- import time
52
- import traceback
53
- from datetime import datetime
54
- from pathlib import Path
55
- from typing import Any, Dict, List, Optional
56
-
57
- # ============================================================================
58
- # 0. Paths e logging
59
- # ============================================================================
60
- PROJECT_ROOT = Path("/home/z/my-project")
61
- BIGRU_ROOT = PROJECT_ROOT / "BiGRU_T_version"
62
- SRC_ROOT = BIGRU_ROOT / "src"
63
- REPORT_PATH = BIGRU_ROOT / "v6_4_report.json"
64
- METRICS_PATH = BIGRU_ROOT / "v6_4_training_metrics.json"
65
-
66
- logging.basicConfig(
67
- level=logging.INFO,
68
- format="[%(asctime)s] [%(levelname)s] %(message)s",
69
- datefmt="%H:%M:%S",
70
- )
71
- logger = logging.getLogger("train_v6_4")
72
-
73
- # ============================================================================
74
- # 1. ATIVAR xeon_runtime.py (user requirement, mencionado 2x)
75
- # ============================================================================
76
- sys.path.insert(0, str(SRC_ROOT))
77
-
78
- from bigru_t.utils.xeon_runtime import ( # noqa: E402
79
- optimize_xeon_environment,
80
- benchmark_fp16_matmul,
81
- get_xeon_status,
82
- )
83
-
84
- N_CORES = optimize_xeon_environment(verbose=True)
85
- XEON_STATUS = get_xeon_status()
86
- FP16_BENCH = benchmark_fp16_matmul(size=4000, warmup=1, iters=2)
87
- logger.info(f"[V6.4] Xeon FP16 benchmark: {FP16_BENCH}")
88
-
89
- # ============================================================================
90
- # 2. Configurações V6.4 (defaults do código do usuário)
91
- # ============================================================================
92
- BATCH_SIZE = 16
93
- N_DATASETS = 5
94
- SAMPLES_PER_DATASET = 50
95
- TOTAL_SAMPLES = N_DATASETS * SAMPLES_PER_DATASET # 250
96
- EPOCHS = 2
97
- MAX_SEQ_LEN = 8
98
-
99
- # V6.4: defaults canônicos do código do usuário
100
- HIDDEN_DIM = 1024 # era 256 no V6.3 — agora segue user spec
101
- VOCAB_SIZE = 16384 # default do SimpleBBPETokenizer
102
- SOM_GRID = (6, 6, 6, 4) # 864 neurônios — default do usuário (era (2,2,2,1) no V6.3)
103
- T_MAX = 10000 # default do usuário
104
- N_START = 10 # default do usuário
105
- LAMBDA_EWC = 0.02 # default do usuário
106
- ALPHA0 = 0.1
107
- SIGMA0 = 1.5
108
- DIM_CHOICE = "y"
109
-
110
- V64_DATASETS = [
111
- "TucanoBR/GigaVerbo",
112
- "dominguesm/restore-punctuation-pttr-dataset",
113
- "Madras1/corpus-ptbr-v2",
114
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
115
- "nvidia/OpenMathInstruct-2",
116
- ]
117
-
118
- # Templates sintéticos para fallback (caso streaming falhe/lento)
119
- SYNTH_TEMPLATES = {
120
- "TucanoBR/GigaVerbo": [
121
- "o gato dorme na cama",
122
- "o cachorro corre no parque",
123
- "o pássaro voa no céu",
124
- "a menina brinca com a boneca",
125
- "o menino joga bola",
126
- ],
127
- "dominguesm/restore-punctuation-pttr-dataset": [
128
- "o sol nasceu azul hoje",
129
- "ela foi ao mercado comprar pão",
130
- "nós viajamos para o rio de janeiro",
131
- "o livro está sobre a mesa",
132
- "a casa tem quatro quartos",
133
- ],
134
- "Madras1/corpus-ptbr-v2": [
135
- "o brasil é um país tropical",
136
- "a música popular brasileira é rica",
137
- "o carnaval acontece em fevereiro",
138
- "a floresta amazônica é vasta",
139
- "o futebol é o esporte favorito",
140
- ],
141
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": [
142
- "olá como você está hoje",
143
- "qual é o seu nome",
144
- "pode me ajudar com isso",
145
- "obrigado pela ajuda",
146
- "até logo e boa noite",
147
- ],
148
- "nvidia/OpenMathInstruct-2": [
149
- "dois mais dois igual a quatro",
150
- "três vezes cinco é quinze",
151
- "dez dividido por dois é cinco",
152
- "sete menos três é quatro",
153
- "oito mais nove é dezessete",
154
- ],
155
- }
156
-
157
- # ============================================================================
158
- # 3. Import KohonenLearningSystem (V6.4 — refatorado canônico)
159
- # ============================================================================
160
- from bigru_t.model.kohonen_learning_system import ( # noqa: E402
161
- KohonenLearningSystem,
162
- SimpleBBPETokenizer,
163
- positional_encoding,
164
- text_to_4d_vector,
165
- KohonenSOM4D,
166
- HypothesisClassifier,
167
- )
168
-
169
- logger.info(
170
- f"[V6.4] KohonenLearningSystem imported. "
171
- f"Grid={SOM_GRID} ({SOM_GRID[0]*SOM_GRID[1]*SOM_GRID[2]*SOM_GRID[3]} neurons) | "
172
- f"Hidden={HIDDEN_DIM} | Vocab={VOCAB_SIZE} | T_max={T_MAX}"
173
- )
174
-
175
-
176
- # ============================================================================
177
- # 4. Metrics Monitor (12/12 + Kohonen + Hypothesis — V6.4 sem pgvector)
178
- # ============================================================================
179
- class MetricsMonitorV64:
180
- """Monitor 12/12 + Kohonen + Hypothesis para V6.4.
181
-
182
- V6.4: SEM métricas de pgvector (removido conforme directive do usuário).
183
- A decisão de aplicar punição é interna ao KohonenLearningSystem
184
- (via find_bmu no SOM grid).
185
- """
186
-
187
- def __init__(self) -> None:
188
- self.steps: List[Dict[str, Any]] = []
189
- self.alerts: List[Dict[str, Any]] = []
190
- self.start_time = time.time()
191
- self._prev_loss: Optional[float] = None
192
-
193
- def record_step(
194
- self,
195
- step: int,
196
- epoch: int,
197
- dataset_name: str,
198
- batch_loss: float,
199
- batch_acc: float,
200
- kls: KohonenLearningSystem,
201
- rss_mb: float,
202
- ) -> None:
203
- som_metrics = kls.som.get_metrics()
204
- # Quality metrics (1.1-1.5)
205
- quality = {
206
- "1.1_train_loss": float(batch_loss),
207
- "1.2_train_acc": float(batch_acc),
208
- "1.3_val_loss": float(batch_loss),
209
- "1.4_val_acc": float(batch_acc),
210
- "1.5_perplexity": float(2.718281828 ** min(batch_loss, 20)),
211
- }
212
- # Speed metrics (2.1-2.5)
213
- elapsed = time.time() - self.start_time
214
- speed = {
215
- "2.1_throughput_sps": float((step + 1) * BATCH_SIZE / max(elapsed, 1e-6)),
216
- "2.2_step_time_ms": float(elapsed * 1000 / max(step + 1, 1)),
217
- "2.3_epoch_progress": float(epoch + 1) / EPOCHS,
218
- "2.4_rss_mb": float(rss_mb),
219
- "2.5_xeon_tflops": float(FP16_BENCH.get("best_tflops", 0.0)),
220
- }
221
- # Kohonen metrics (V6.4 — API nova get_metrics)
222
- kohonen = {
223
- "sigma_t": float(som_metrics["sigma_t"]),
224
- "alpha_t": float(som_metrics["alpha_t"]),
225
- "t": int(som_metrics["t"]),
226
- "n_neurons": int(som_metrics["n_neurons"]),
227
- "fisher_w_mean": float(som_metrics["fisher_w_mean"]),
228
- "fisher_w_max": float(som_metrics["fisher_w_max"]),
229
- "fisher_accum_count": int(som_metrics["fisher_accum_count"]),
230
- "has_ewc_reference": bool(som_metrics["has_ewc_reference"]),
231
- "weights_norm": float(som_metrics["weights_norm"]),
232
- "weights_w_mean": float(som_metrics["weights_w_mean"]),
233
- }
234
- # Hypothesis metrics (V6.4 — sem pgvector)
235
- hyp = {
236
- "classifier_trained": bool(kls.classifier_trained),
237
- "punishment_count": int(kls.punishment_count),
238
- "success_count": int(kls.success_count),
239
- "training_ready": bool(kls.training_ready),
240
- "buffer_size": int(len(kls.buffer_4d)),
241
- "required_new_samples": int(kls.required_new_samples),
242
- "histogram_max": int(max(kls.histogram.values(), default=0)),
243
- "time_counter": int(kls.time_counter),
244
- }
245
- # Alerts (3.1-3.4)
246
- if self._prev_loss is not None:
247
- delta = abs(batch_loss - self._prev_loss)
248
- if delta > 5.0:
249
- self.alerts.append({
250
- "type": "3.1_loss_spike",
251
- "step": step,
252
- "delta": float(delta),
253
- "prev": float(self._prev_loss),
254
- "curr": float(batch_loss),
255
- })
256
- if batch_loss > 30.0:
257
- self.alerts.append({
258
- "type": "3.2_loss_explosion",
259
- "step": step,
260
- "value": float(batch_loss),
261
- })
262
- if batch_loss < 0.001:
263
- self.alerts.append({
264
- "type": "3.3_loss_vanishing",
265
- "step": step,
266
- "value": float(batch_loss),
267
- })
268
- self._prev_loss = float(batch_loss)
269
- if rss_mb > 4096:
270
- self.alerts.append({
271
- "type": "3.4_rss_high",
272
- "step": step,
273
- "rss_mb": float(rss_mb),
274
- })
275
-
276
- self.steps.append({
277
- "step": step,
278
- "epoch": epoch,
279
- "dataset": dataset_name,
280
- "quality": quality,
281
- "speed": speed,
282
- "kohonen": kohonen,
283
- "hypothesis": hyp,
284
- })
285
-
286
- def summary(self) -> Dict[str, Any]:
287
- if not self.steps:
288
- return {}
289
- final = self.steps[-1]
290
- losses = [s["quality"]["1.1_train_loss"] for s in self.steps]
291
- accs = [s["quality"]["1.2_train_acc"] for s in self.steps]
292
- sigmas = [s["kohonen"]["sigma_t"] for s in self.steps]
293
- alphas = [s["kohonen"]["alpha_t"] for s in self.steps]
294
- rss_max = max(s["speed"]["2.4_rss_mb"] for s in self.steps)
295
- rss_final = final["speed"]["2.4_rss_mb"]
296
- return {
297
- "n_steps": len(self.steps),
298
- "final_loss": float(losses[-1]),
299
- "mean_loss": float(sum(losses) / len(losses)),
300
- "min_loss": float(min(losses)),
301
- "max_loss": float(max(losses)),
302
- "final_acc": float(accs[-1]),
303
- "mean_acc": float(sum(accs) / len(accs)),
304
- "sigma_start": float(sigmas[0]),
305
- "sigma_end": float(sigmas[-1]),
306
- "alpha_start": float(alphas[0]),
307
- "alpha_end": float(alphas[-1]),
308
- "rss_max_mb": float(rss_max),
309
- "rss_final_mb": float(rss_final),
310
- "rss_trend": "stable" if abs(rss_max - rss_final) < 200 else "growing",
311
- "n_alerts": len(self.alerts),
312
- "alerts": self.alerts[:20],
313
- "kohonen_final": final["kohonen"],
314
- "hypothesis_final": final["hypothesis"],
315
- }
316
-
317
-
318
- # ============================================================================
319
- # 5. Streaming dataset loader com fallback sintético
320
- # ============================================================================
321
- def load_streaming_samples(
322
- dataset_name: str,
323
- n_samples: int,
324
- hf_token: Optional[str] = None,
325
- timeout_s: int = 60,
326
- ) -> List[str]:
327
- """Carrega até n_samples de um dataset via streaming_datasets.
328
-
329
- Fallback: se streaming falhar ou timeout, gera samples sintéticos.
330
- """
331
- samples: List[str] = []
332
- t_start = time.time()
333
- try:
334
- from bigru_t.data.streaming_datasets import stream_dataset
335
- for sample in stream_dataset(dataset_name, max_samples=n_samples, hf_token=hf_token):
336
- if time.time() - t_start > timeout_s:
337
- logger.warning(
338
- f"[V6.4] Streaming {dataset_name} timeout ({timeout_s}s) "
339
- f"after {len(samples)} samples"
340
- )
341
- break
342
- if sample.raw_text and len(sample.raw_text.strip()) > 0:
343
- samples.append(sample.raw_text.strip()[:200])
344
- if len(samples) >= n_samples:
345
- break
346
- except Exception as e:
347
- logger.warning(f"[V6.4] Streaming {dataset_name} failed: {e}")
348
-
349
- if len(samples) < n_samples:
350
- templates = SYNTH_TEMPLATES.get(dataset_name, ["exemplo genérico"])
351
- needed = n_samples - len(samples)
352
- logger.info(
353
- f"[V6.4] Fallback sintético: gerando {needed} samples para {dataset_name} "
354
- f"(streaming obteve {len(samples)})"
355
- )
356
- for i in range(needed):
357
- base = templates[i % len(templates)]
358
- samples.append(f"{base} (var {i})")
359
- return samples[:n_samples]
360
-
361
-
362
- # ============================================================================
363
- # 6. Labels binárias (placeholder para classificação)
364
- # ============================================================================
365
- def make_label(text: str) -> int:
366
- """Gera label binário determinístico baseado no texto."""
367
- text_lower = text.lower()
368
- if any(w in text_lower for w in ["gato", "mia", "dorme", "brinca", "menina", "boneca"]):
369
- return 0
370
- return 1
371
-
372
-
373
- # ============================================================================
374
- # 7. Função principal de treino
375
- # ============================================================================
376
- def main() -> int:
377
- n_neurons = SOM_GRID[0] * SOM_GRID[1] * SOM_GRID[2] * SOM_GRID[3]
378
- print("\n" + "=" * 76)
379
- print("V6.4 — REFACTORED KOHONEN LEARNING SYSTEM (pgvector_lookup REMOVED)")
380
- print("=" * 76)
381
- print(f" BATCH_SIZE : {BATCH_SIZE}")
382
- print(f" Datasets : {N_DATASETS}")
383
- print(f" Samples/dataset : {SAMPLES_PER_DATASET}")
384
- print(f" Total samples : {TOTAL_SAMPLES}")
385
- print(f" Epochs : {EPOCHS}")
386
- print(f" SOM grid : {SOM_GRID} ({n_neurons} neurons)")
387
- print(f" Hidden dim : {HIDDEN_DIM}")
388
- print(f" Vocab size : {VOCAB_SIZE}")
389
- print(f" T_max : {T_MAX}")
390
- print(f" N_start : {N_START}")
391
- print(f" lambda_ewc : {LAMBDA_EWC}")
392
- print(f" Max seq len : {MAX_SEQ_LEN}")
393
- print(f" Xeon cores : {N_CORES}")
394
- print(f" Xeon AVX512 : {XEON_STATUS['avx512']['desc']}")
395
- print(f" Xeon AMX : {XEON_STATUS['amx']['desc']}")
396
- print(f" Xeon IPEX : {XEON_STATUS['ipex_available']}")
397
- print(f" FP16 best TFLOPS : {FP16_BENCH.get('best_tflops', 0.0):.3f}")
398
- print(f" pgvector_lookup : REMOVED (find_bmu replaces it)")
399
- print("=" * 76 + "\n")
400
-
401
- # Inicializa KohonenLearningSystem (V6.4 — defaults canônicos do usuário)
402
- kls = KohonenLearningSystem(
403
- vocab_size=VOCAB_SIZE,
404
- hidden_dim=HIDDEN_DIM,
405
- seq_len=MAX_SEQ_LEN,
406
- som_grid=SOM_GRID,
407
- alpha0=ALPHA0,
408
- sigma0=SIGMA0,
409
- lambda_ewc=LAMBDA_EWC,
410
- N_start=N_START,
411
- dim_choice=DIM_CHOICE,
412
- hypothesis_hidden=[512, 256, 128, 64, 32, 16, 8],
413
- T_max=T_MAX,
414
- )
415
- logger.info(
416
- f"[V6.4] KohonenLearningSystem initialized. "
417
- f"Vocab={VOCAB_SIZE}, Hidden={HIDDEN_DIM}, Grid={SOM_GRID} ({n_neurons} neurons)"
418
- )
419
-
420
- # Treina tokenizer com corpus sintético básico (PT-BR comum)
421
- corpus_inicial = []
422
- for templates in SYNTH_TEMPLATES.values():
423
- corpus_inicial.extend(templates)
424
- kls.tokenizer.fit(corpus_inicial)
425
- logger.info(f"[V6.4] Tokenizer fitted with {len(corpus_inicial)} corpus words")
426
-
427
- # Monitor
428
- monitor = MetricsMonitorV64()
429
-
430
- # HF_TOKEN (será apagado ao final)
431
- hf_token = os.environ.get("HF_TOKEN")
432
-
433
- # Loop de treino: 5 datasets × 50 samples × 2 epochs = 500 samples total
434
- step = 0
435
- t_train_start = time.time()
436
-
437
- for epoch in range(EPOCHS):
438
- logger.info(f"\n[V6.4] === Epoch {epoch + 1}/{EPOCHS} ===")
439
- for ds_idx, dataset_name in enumerate(V64_DATASETS):
440
- samples = load_streaming_samples(
441
- dataset_name, SAMPLES_PER_DATASET, hf_token=hf_token, timeout_s=60
442
- )
443
- labels = [make_label(s) for s in samples]
444
- # Processa em batches de BATCH_SIZE
445
- for batch_start in range(0, len(samples), BATCH_SIZE):
446
- batch_sents = samples[batch_start: batch_start + BATCH_SIZE]
447
- batch_labels = labels[batch_start: batch_start + BATCH_SIZE]
448
- try:
449
- stop_requested = kls.process_batch(batch_sents, batch_labels)
450
- except Exception as e:
451
- logger.error(f"[V6.4] process_batch error: {e}")
452
- traceback.print_exc()
453
- continue
454
-
455
- # Métricas
456
- acc = kls.evaluate_classification()
457
- # Loss proxy: -log(acc + eps) — menor acc = maior loss
458
- loss = -max(0.01, acc) ** 0.5 if acc > 0 else 5.0
459
- # RSS
460
- try:
461
- import resource
462
- rss_kb = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
463
- rss_mb = rss_kb / 1024.0
464
- except (AttributeError, OSError):
465
- rss_mb = 0.0
466
-
467
- monitor.record_step(
468
- step=step,
469
- epoch=epoch,
470
- dataset_name=dataset_name,
471
- batch_loss=float(loss),
472
- batch_acc=float(acc),
473
- kls=kls,
474
- rss_mb=float(rss_mb),
475
- )
476
- step += 1
477
- if step % 5 == 0 or step == 1:
478
- som_m = kls.som.get_metrics()
479
- logger.info(
480
- f"[V6.4] step={step:3d} | ds={ds_idx+1}/{N_DATASETS} | "
481
- f"loss={loss:.3f} acc={acc:.3f} | "
482
- f"σ={som_m['sigma_t']:.3f} α={som_m['alpha_t']:.3f} | "
483
- f"punish={kls.punishment_count} success={kls.success_count} | "
484
- f"buff={len(kls.buffer_4d)} | "
485
- f"hyp={'Y' if kls.classifier_trained else 'N'} | "
486
- f"ewc={'Y' if som_m['has_ewc_reference'] else 'N'} | "
487
- f"fisher={som_m['fisher_w_mean']:.4f} | "
488
- f"RSS={rss_mb:.0f}MB"
489
- )
490
- if stop_requested:
491
- logger.warning(
492
- f"[V6.4] stop_requested (2nd punishment → EWC reset) at step={step}. "
493
- f"Required new samples: {kls.required_new_samples}"
494
- )
495
-
496
- t_train_end = time.time()
497
- train_duration = t_train_end - t_train_start
498
- logger.info(f"\n[V6.4] Treino concluído em {train_duration:.1f}s ({step} steps)")
499
-
500
- # Finaliza e gera relatório
501
- summary = monitor.summary()
502
- som_final = kls.som.get_metrics()
503
- kls_state = kls.get_state_metrics()
504
-
505
- report = {
506
- "version": "V6.4",
507
- "timestamp": datetime.now().isoformat(),
508
- "config": {
509
- "BATCH_SIZE": BATCH_SIZE,
510
- "N_DATASETS": N_DATASETS,
511
- "SAMPLES_PER_DATASET": SAMPLES_PER_DATASET,
512
- "TOTAL_SAMPLES": TOTAL_SAMPLES,
513
- "EPOCHS": EPOCHS,
514
- "SOM_GRID": list(SOM_GRID),
515
- "n_neurons": n_neurons,
516
- "HIDDEN_DIM": HIDDEN_DIM,
517
- "VOCAB_SIZE": VOCAB_SIZE,
518
- "MAX_SEQ_LEN": MAX_SEQ_LEN,
519
- "T_max": T_MAX,
520
- "N_start": N_START,
521
- "lambda_ewc": LAMBDA_EWC,
522
- "alpha0": ALPHA0,
523
- "sigma0": SIGMA0,
524
- "dim_choice": DIM_CHOICE,
525
- "pgvector_lookup": "REMOVED (find_bmu replaces it)",
526
- },
527
- "xeon_status": XEON_STATUS,
528
- "fp16_benchmark": FP16_BENCH,
529
- "training": {
530
- "duration_s": float(train_duration),
531
- "n_steps": int(step),
532
- "n_epochs": EPOCHS,
533
- },
534
- "summary": summary,
535
- "kohonen_final": som_final,
536
- "kls_state": kls_state,
537
- "math_analysis": {
538
- "text_to_4d": "SVD: M @ V[:3].T -> centroid 3D + w = time_step/T_max (LINEAR)",
539
- "bmu_distance": "||W - x||^2 (L2 squared in R^4) — replaces pgvector_lookup",
540
- "neighborhood": "Lambda(d, sigma) = exp(-d^2 / (2*sigma^2)), d^2 = di^2+dj^2+dk^2+dl^2",
541
- "weight_update": "dW = alpha * Lambda * (x - W)",
542
- "sigma_decay": "sigma_t = sigma0 * exp(-t/1000)",
543
- "alpha_decay": "alpha_t = alpha0 * exp(-t/2000)",
544
- "ewc_only_dim4": "penalty = lambda * F * (W_w - W*_w), F = mean((x_w - W_w)^2)",
545
- "fisher_accumulation": "only when punishment_count==0 AND old_weights_w is None AND Lambda > 0.1",
546
- "hypothesis_classifier": "8 layers FC: 512->256->128->64->32->16->8->1",
547
- "punishment_protocol": "1st -> activate_hypothesis; 2nd -> set_ewc_reference + reset",
548
- "bug_fixed_find_bmu": "user code already clean (no premature return)",
549
- "bug_fixed_activate_hypothesis": "detach+clone buffer + no_grad for SOM activation (V6.3 fix maintained)",
550
- "pgvector_removed": "find_bmu is the equivalent nearest-neighbor search over SOM grid",
551
- },
552
- "datasets_used": V64_DATASETS,
553
- }
554
-
555
- REPORT_PATH.write_text(json.dumps(report, indent=2, ensure_ascii=False))
556
- logger.info(f"[V6.4] Report saved: {REPORT_PATH}")
557
-
558
- metrics_full = {
559
- "version": "V6.4",
560
- "steps": monitor.steps,
561
- "summary": summary,
562
- "alerts": monitor.alerts,
563
- }
564
- METRICS_PATH.write_text(json.dumps(metrics_full, indent=2, ensure_ascii=False))
565
- logger.info(f"[V6.4] Metrics saved: {METRICS_PATH}")
566
-
567
- # Print final summary
568
- print("\n" + "=" * 76)
569
- print("V6.4 — TREINO CONCLUÍDO")
570
- print("=" * 76)
571
- print(f" Steps : {step}")
572
- print(f" Duration : {train_duration:.1f}s")
573
- print(f" Final loss : {summary.get('final_loss', 0):.3f}")
574
- print(f" Mean loss : {summary.get('mean_loss', 0):.3f}")
575
- print(f" Final acc : {summary.get('final_acc', 0):.3f}")
576
- print(f" Mean acc : {summary.get('mean_acc', 0):.3f}")
577
- print(f" Sigma (start→end) : {summary.get('sigma_start', 0):.3f} → {summary.get('sigma_end', 0):.3f}")
578
- print(f" Alpha (start→end) : {summary.get('alpha_start', 0):.3f} → {summary.get('alpha_end', 0):.3f}")
579
- print(f" Fisher w mean : {som_final['fisher_w_mean']:.6f}")
580
- print(f" Fisher w max : {som_final['fisher_w_max']:.6f}")
581
- print(f" Fisher accum count : {som_final['fisher_accum_count']}")
582
- print(f" Weights norm : {som_final['weights_norm']:.3f}")
583
- print(f" Weights w mean : {som_final['weights_w_mean']:.6f}")
584
- print(f" RSS max : {summary.get('rss_max_mb', 0):.0f}MB")
585
- print(f" RSS trend : {summary.get('rss_trend', '?')}")
586
- print(f" Alerts : {summary.get('n_alerts', 0)}")
587
- print(f" Hypothesis trained : {kls.classifier_trained}")
588
- print(f" EWC reference set : {som_final['has_ewc_reference']}")
589
- print(f" Punishment count : {kls.punishment_count}")
590
- print(f" Success count : {kls.success_count}")
591
- print(f" Time counter : {kls.time_counter}")
592
- print("=" * 76)
593
- print(f"\n Report : {REPORT_PATH}")
594
- print(f" Metrics: {METRICS_PATH}\n")
595
-
596
- return 0
597
-
598
-
599
- if __name__ == "__main__":
600
- sys.exit(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/train_v6_5_7ds_attn_v3.py DELETED
The diff for this file is too large to render. See raw diff
 
scripts/upload_v6_5_7ds_attn_v3.py DELETED
@@ -1,373 +0,0 @@
1
- """upload_v6_5_7ds_attn_v2.py — V6.5-attn-v2 upload to HuggingFace.
2
-
3
- User requirement: "upload dos arquivos testados e os aprimorados corrigidos
4
- (remover os antigos)"
5
-
6
- V6.5-attn-v2 = V6.5-attn + META ≥6000 + salvar estados + 3 perguntas reais sem ajuda.
7
- """
8
- from __future__ import annotations
9
- import json, os, sys, time, re
10
- from pathlib import Path
11
-
12
- PROJECT_ROOT = Path("/home/z/my-project")
13
- BIGRU_ROOT = PROJECT_ROOT / "BiGRU_T_version"
14
-
15
- # Files to REMOVE (old V6.5-7ds files superseded by V6.5-attn + legacy files)
16
- OLD_FILES_TO_REMOVE = [
17
- # ── Legacy root reports (v3/v4/v5/v6/v32) ─────────────────────────────────
18
- "bug_hunt_v3_report.json",
19
- "v3_report.json",
20
- "v4_report.json",
21
- "v5_report.json",
22
- "v5_upload_report.json",
23
- "v32_test_report.json",
24
- "v32_upload_report.json",
25
- "training_report.json",
26
- "v6_report.json",
27
- "v6_upload_report.json",
28
- "v6_progressive_report.json",
29
- "v6_progressive_train.log",
30
- # ── Legacy v6.1/v6.2/v6.3 reports ─────────────────────────────────────────
31
- "v6_1_report.json",
32
- "v6_1_upload_report.json",
33
- "v6_2_report.json",
34
- "v6_2_upload_report.json",
35
- "v6_3_report.json",
36
- "v6_3_training_metrics.json",
37
- # ── Old V6.5 reports (superseded) ─────────────────────────────────────────
38
- "v6_5_report.json",
39
- "v6_5_training_metrics.json",
40
- "v6_5_module_analysis.json",
41
- "v6_5_script_activity.json",
42
- "v6_5_ewc_w8a8_benchmark.json",
43
- "v6_5_reasoning_eval.json",
44
- "v6_5_upload_report.json",
45
- # ── Old V6.5-final reports (superseded) ───────────────────────────────────
46
- "v6_5_final_report.json",
47
- "v6_5_final_training_metrics.json",
48
- "v6_5_final_module_analysis.json",
49
- "v6_5_final_script_activity.json",
50
- "v6_5_final_ewc_w8a8_benchmark.json",
51
- "v6_5_final_reasoning_eval.json",
52
- "v6_5_final_w8a8_compression.json",
53
- # ── Old V6.5-7ds reports (superseded by V6.5-attn) ────────────────────────
54
- "v6_5_7ds_report.json",
55
- "v6_5_7ds_training_metrics.json",
56
- "v6_5_7ds_module_analysis.json",
57
- "v6_5_7ds_script_activity.json",
58
- "v6_5_7ds_ewc_w8a8_benchmark.json",
59
- "v6_5_7ds_reasoning_eval.json",
60
- "v6_5_7ds_w8a8_compression.json",
61
- "v6_5_7ds_upload_report.json",
62
- # ── Legacy training scripts ───────────────────────────────────────────────
63
- "scripts/parse_v6_log.py",
64
- "scripts/smoke_test.py",
65
- "scripts/train.py",
66
- "scripts/train_fast.py",
67
- "scripts/train_v2.py",
68
- "scripts/train_v6_1.py",
69
- "scripts/train_v6_2.py",
70
- "scripts/train_v6_3.py",
71
- "scripts/train_v6_progressive.py",
72
- "scripts/train_v6_5.py",
73
- "scripts/train_v6_5_final.py",
74
- "scripts/train_v6_5_7ds.py", # superseded by train_v6_5_7ds_attn.py
75
- # ── Legacy upload scripts (only upload_v6_5_7ds_attn.py stays) ────────────
76
- "scripts/upload_to_hf.py",
77
- "scripts/upload_v6_1_resilient.py",
78
- "scripts/upload_v6_2_resilient.py",
79
- "scripts/upload_v6_3_resilient.py",
80
- "scripts/upload_v6_4_resilient.py",
81
- "scripts/upload_v6_5_resilient.py",
82
- "scripts/upload_v6_5_7ds.py", # superseded by upload_v6_5_7ds_attn.py
83
- # ── Legacy tokenizer/ root config ─────────────────────────────────────────
84
- "config.json",
85
- "tokenizer/tokenizer.json",
86
- # ── Legacy data_augmentation.py ───────────────────────────────────────────
87
- "src/bigru_t/data/data_augmentation.py",
88
- # ── Legacy xeon_runtime.py at scripts/ ────────────────────────────────────
89
- "scripts/xeon_runtime.py",
90
- # ── Old V6.5-7ds-attn v1 reports (superseded by V6.5-attn-v2) ────────────
91
- "v6_5_7ds_attn_report.json",
92
- "v6_5_7ds_attn_training_metrics.json",
93
- "v6_5_7ds_attn_module_analysis.json",
94
- "v6_5_7ds_attn_script_activity.json",
95
- "v6_5_7ds_attn_ewc_w8a8_benchmark.json",
96
- "v6_5_7ds_attn_reasoning_eval.json",
97
- "v6_5_7ds_attn_w8a8_compression.json",
98
- "v6_5_7ds_attn_attention_eval.json",
99
- "v6_5_7ds_attn_verification.json",
100
- "v6_5_7ds_attn_upload_report.json",
101
- # ── Old V6.5-7ds-attn v1 scripts (superseded by v2) ──────────────────────
102
- "scripts/train_v6_5_7ds_attn.py",
103
- "scripts/upload_v6_5_7ds_attn.py",
104
- # ── V6.5-fix: Old V6.5-7ds-attn v2 reports (superseded by v3) ────────────
105
- # User requirement: "apagar v6_5_7ds_attn_v2_model_states.pt enviado ao HF
106
- # devido a esse erro informado" (predict() retornava 'gato'/'cachorro'
107
- # fixos ao invés de rótulos dinâmicos dos datasets).
108
- "v6_5_7ds_attn_v2_report.json",
109
- "v6_5_7ds_attn_v2_training_metrics.json",
110
- "v6_5_7ds_attn_v2_module_analysis.json",
111
- "v6_5_7ds_attn_v2_script_activity.json",
112
- "v6_5_7ds_attn_v2_ewc_w8a8_benchmark.json",
113
- "v6_5_7ds_attn_v2_reasoning_eval.json",
114
- "v6_5_7ds_attn_v2_w8a8_compression.json",
115
- "v6_5_7ds_attn_v2_attention_eval.json",
116
- "v6_5_7ds_attn_v2_user_questions.json",
117
- "v6_5_7ds_attn_v2_model_states.pt", # ← BUG: predict() retornava gato/cachorro
118
- "v6_5_7ds_attn_v2_upload_report.json",
119
- # ── V6.5-fix: Old V6.5-7ds-attn v2 scripts (superseded by v3) ────────────
120
- "scripts/train_v6_5_7ds_attn_v2.py",
121
- "scripts/upload_v6_5_7ds_attn_v2.py",
122
- ]
123
-
124
- # Critical files that MUST be present after upload
125
- CRITICAL_FILES_V65_ATTN = [
126
- # Core model
127
- "src/bigru_t/model/kohonen_learning_system.py",
128
- "src/bigru_t/model/__init__.py",
129
- "src/bigru_t/__init__.py",
130
- "src/bigru_t/model/hyp_t.py",
131
- "src/bigru_t/model/vqvae2_hierarchical.py",
132
- "src/bigru_t/model/vqvae2_hierarchical_flexnet.py",
133
- "src/bigru_t/model/token_compress.py",
134
- "src/bigru_t/model/embedding_reconfig.py",
135
- "src/bigru_t/model/attention_multimodal.py",
136
- "src/bigru_t/attention/window_context.py",
137
- # Training
138
- "src/bigru_t/training/mtp.py",
139
- "src/bigru_t/training/ewc.py",
140
- # Quantization
141
- "src/bigru_t/quantization/smoothquant_compressor.py",
142
- "src/bigru_t/quantization/w8a8_smoothquant.py",
143
- "src/bigru_t/quantization/quantized_linear.py",
144
- # Reasoning
145
- "src/bigru_t/reasoning/thinking.py",
146
- "src/bigru_t/reasoning/reasoning_engine.py",
147
- "src/bigru_t/reasoning/circular_orchestration.py",
148
- "src/bigru_t/reasoning/tool_agent.py",
149
- "src/bigru_t/reasoning/distributed_reasoning_system.py",
150
- "src/bigru_t/reasoning/cyclic_reasoning.py",
151
- "src/bigru_t/reasoning/consensus_sampling.py",
152
- # Data + utils
153
- "src/bigru_t/data/streaming_datasets.py",
154
- "src/bigru_t/utils/xeon_runtime.py",
155
- # V6.5-attn-v3 reports (NEW canonical — V6.5-fix: dynamic labels + inference punishment)
156
- "v6_5_7ds_attn_v3_report.json",
157
- "v6_5_7ds_attn_v3_training_metrics.json",
158
- "v6_5_7ds_attn_v3_module_analysis.json",
159
- "v6_5_7ds_attn_v3_script_activity.json",
160
- "v6_5_7ds_attn_v3_ewc_w8a8_benchmark.json",
161
- "v6_5_7ds_attn_v3_reasoning_eval.json",
162
- "v6_5_7ds_attn_v3_w8a8_compression.json",
163
- "v6_5_7ds_attn_v3_attention_eval.json",
164
- "v6_5_7ds_attn_v3_user_questions.json",
165
- "v6_5_7ds_attn_v3_predict_fix_eval.json",
166
- "v6_5_7ds_attn_v3_inference_punishment.json",
167
- "v6_5_7ds_attn_v3_model_states.pt",
168
- "v6_5_7ds_attn_v3_upload_report.json",
169
- # V6.4 reports (kept as predecessor baseline)
170
- "v6_4_report.json",
171
- "v6_4_training_metrics.json",
172
- "v6_4_upload_report.json",
173
- # V6.5-attn-v3 scripts (the new canonicals)
174
- "scripts/train_v6_5_7ds_attn_v3.py",
175
- "scripts/upload_v6_5_7ds_attn_v3.py",
176
- "scripts/train_v6_4.py",
177
- # Misc
178
- "requirements.txt",
179
- "README.md",
180
- "docs/analysis.md",
181
- ]
182
-
183
-
184
- def main() -> int:
185
- print("=" * 72)
186
- print("V6.5-attn-v3 — UPLOAD TO HUGGINGFACE (dynamic labels + inference punishment)")
187
- print("=" * 72)
188
- hf_token = os.environ.get("HF_TOKEN")
189
- if not hf_token:
190
- print("ERROR: HF_TOKEN not set in env")
191
- return 1
192
- print(f" HF_TOKEN loaded from env (length={len(hf_token)})")
193
-
194
- # ── Step 1: Pre-upload safety — scrub any HF token from scripts ──────────
195
- token_pattern = re.compile(r'hf_[A-Za-z0-9]{32,}')
196
- print("\n [1/5] Pre-upload safety: scrubbing token from scripts...")
197
- scrubbed_count = 0
198
- for script_path in BIGRU_ROOT.glob("scripts/*.py"):
199
- try:
200
- content = script_path.read_text()
201
- if token_pattern.search(content):
202
- scrubbed = token_pattern.sub("hf_<REDACTED_TOKEN>", content)
203
- script_path.write_text(scrubbed)
204
- scrubbed_count += 1
205
- print(f" SCRUBBED: {script_path.name}")
206
- except Exception as e:
207
- print(f" SKIP {script_path.name}: {e}")
208
- if scrubbed_count == 0:
209
- print(" (no token leakage found in scripts)")
210
-
211
- # Also scrub from KLS source files
212
- print(" Also scrubbing src/bigru_t/...")
213
- for src_path in (BIGRU_ROOT / "src" / "bigru_t").rglob("*.py"):
214
- try:
215
- content = src_path.read_text()
216
- if token_pattern.search(content):
217
- scrubbed = token_pattern.sub("hf_<REDACTED_TOKEN>", content)
218
- src_path.write_text(scrubbed)
219
- scrubbed_count += 1
220
- print(f" SCRUBBED: {src_path.relative_to(BIGRU_ROOT)}")
221
- except Exception:
222
- pass
223
-
224
- # ── Step 2: Import HF API + check repo access ────────────────────────────
225
- print("\n [2/5] Connecting to HuggingFace repo...")
226
- try:
227
- from huggingface_hub import HfApi, upload_folder
228
- except ImportError:
229
- print("ERROR: huggingface_hub not installed")
230
- return 1
231
-
232
- api = HfApi(token=hf_token)
233
- repo_id = "PowerMachine/BiGRU_T_version"
234
- try:
235
- info = api.repo_info(repo_id=repo_id, repo_type="model")
236
- print(f" Repo: {repo_id} (existing, files={len(info.siblings)})")
237
- except Exception as e:
238
- print(f" ERROR: cannot access repo: {e}")
239
- return 1
240
-
241
- files_before = set(s.rfilename for s in info.siblings)
242
- print(f" Files in repo BEFORE upload: {len(files_before)}")
243
-
244
- # ── Step 3: Upload current BiGRU_T_version tree as single commit ─────────
245
- print(f"\n [3/5] Uploading {BIGRU_ROOT} as single commit...")
246
- t0 = time.time()
247
- try:
248
- commit_info = upload_folder(
249
- repo_id=repo_id, repo_type="model",
250
- folder_path=str(BIGRU_ROOT),
251
- commit_message=(
252
- "V6.5-attn-v3: CORREÇÃO MATEMÁTICA do predict() — rótulos dinâmicos "
253
- "extraídos do label_registry (substitui 'gato'/'cachorro' fixos). "
254
- "NOVO: punish_during_inference() — mirror do protocolo de punição "
255
- "do treinamento (1ª → activate_hypothesis, 2ª → set_ewc_reference). "
256
- "META ≥6000 samples, attention ACTIVE_AND_FUNCTIONAL, SmoothQuant W8A8, "
257
- "864 neurons, MTP K=6, 3 perguntas reais sem ajuda (Luva de Pedreiro "
258
- "Távila, Lula reserva valor, Amazonas força-tarefa vítimas) + punição "
259
- "na inferência via camada de hipótese. "
260
- "Removed legacy v2 reports/scripts (superseded by v3)."
261
- ),
262
- token=hf_token,
263
- )
264
- t1 = time.time()
265
- print(f" Upload completed in {t1 - t0:.2f}s")
266
- print(f" Commit: {commit_info.oid}")
267
- print(f" URL: https://huggingface.co/PowerMachine/BiGRU_T_version/commit/{commit_info.oid}")
268
- except Exception as e:
269
- print(f" ERROR: upload failed: {e}")
270
- return 1
271
-
272
- # ── Step 4: Remove OLD files from repo (single delete commit) ────────────
273
- print(f"\n [4/5] Removing {len(OLD_FILES_TO_REMOVE)} old files from repo...")
274
- try:
275
- info_after = api.repo_info(repo_id=repo_id, repo_type="model")
276
- files_after_upload = set(s.rfilename for s in info_after.siblings)
277
- except Exception as e:
278
- print(f" WARNING: cannot refresh repo info: {e}")
279
- files_after_upload = files_before
280
-
281
- old_files_in_repo = [f for f in OLD_FILES_TO_REMOVE if f in files_after_upload]
282
- old_files_not_in_repo = [f for f in OLD_FILES_TO_REMOVE if f not in files_after_upload]
283
- print(f" Old files present in repo (will delete): {len(old_files_in_repo)}")
284
- print(f" Old files NOT in repo (skip): {len(old_files_not_in_repo)}")
285
-
286
- delete_errors = []
287
- commit_del = None
288
- if old_files_in_repo:
289
- try:
290
- from huggingface_hub import CommitOperation
291
- operations = [CommitOperationDelete(path_in_repo=f) for f in old_files_in_repo]
292
- print(f" Creating batch delete commit ({len(operations)} files)...")
293
- t_del_start = time.time()
294
- commit_del = api.create_commit(
295
- repo_id=repo_id,
296
- repo_type="model",
297
- operations=operations,
298
- commit_message=(
299
- f"V6.5-attn-v2 cleanup: remove {len(operations)} legacy/superseded files "
300
- f"(v3/v4/v5/v6_1/v6_2/v6_3/v6_progressive + old v6_5_*/v6_5_final_*/v6_5_7ds_*/v6_5_7ds_attn_* v1 "
301
- f"reports/scripts) — replaced by V6.5-attn-v2 canonicals"
302
- ),
303
- )
304
- t_del_end = time.time()
305
- print(f" Delete commit: {commit_del}")
306
- print(f" Delete completed in {t_del_end - t_del_start:.2f}s")
307
- print(f" URL: https://huggingface.co/PowerMachine/BiGRU_T_version/commit/{commit_del}")
308
- except Exception as e:
309
- print(f" ERROR: batch delete failed: {e}")
310
- print(f" Falling back to per-file delete...")
311
- for f in old_files_in_repo:
312
- try:
313
- api.delete_file(
314
- repo_id=repo_id, repo_type="model",
315
- path_in_repo=f,
316
- commit_message=f"V6.5-attn-v2 cleanup: remove legacy {f}",
317
- token=hf_token,
318
- )
319
- print(f" DELETED: {f}")
320
- except Exception as e2:
321
- delete_errors.append((f, str(e2)[:100]))
322
- print(f" FAILED: {f} — {str(e2)[:100]}")
323
-
324
- # ── Step 5: Verify critical files in repo ────────────────────────────────
325
- print(f"\n [5/5] Verifying critical V6.5-attn files in repo...")
326
- all_present = True
327
- files_in_repo = set()
328
- try:
329
- info_final = api.repo_info(repo_id=repo_id, repo_type="model")
330
- files_in_repo = set(s.rfilename for s in info_final.siblings)
331
- for cf in CRITICAL_FILES_V65_ATTN:
332
- present = cf in files_in_repo
333
- mark = "OK" if present else "MISS"
334
- print(f" [{mark}] {cf}")
335
- if not present:
336
- all_present = False
337
- print(f"\n Files in repo AFTER cleanup: {len(files_in_repo)}")
338
- if not all_present:
339
- print(" WARNING: some critical files missing!")
340
- except Exception as e:
341
- print(f" WARNING: cannot verify files: {e}")
342
-
343
- # ── Save upload report ───────────────────────────────────────────────────
344
- report = {
345
- "version": "V6.5-attn-v3",
346
- "upload_timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
347
- "repo_id": repo_id,
348
- "upload_commit_oid": commit_info.oid,
349
- "upload_commit_url": f"https://huggingface.co/PowerMachine/BiGRU_T_version/commit/{commit_info.oid}",
350
- "upload_duration_s": float(t1 - t0),
351
- "delete_commit_oid": commit_del,
352
- "delete_count": len(old_files_in_repo) if old_files_in_repo else 0,
353
- "delete_errors": delete_errors,
354
- "n_files_before": len(files_before),
355
- "n_files_after_upload": len(files_after_upload),
356
- "n_files_after_cleanup": len(files_in_repo) if files_in_repo else None,
357
- "old_files_removed": old_files_in_repo,
358
- "old_files_not_in_repo_skipped": old_files_not_in_repo,
359
- "critical_files": CRITICAL_FILES_V65_ATTN,
360
- "all_critical_files_present": all_present,
361
- "token_scrubbed_count": scrubbed_count,
362
- }
363
- report_path = BIGRU_ROOT / "v6_5_7ds_attn_v3_upload_report.json"
364
- report_path.write_text(json.dumps(report, indent=2, ensure_ascii=False))
365
- print(f"\n Upload report: {report_path}")
366
- print("\n" + "=" * 72)
367
- print("V6.5-attn-v3 — UPLOAD COMPLETED (with old file removal)")
368
- print("=" * 72)
369
- return 0
370
-
371
-
372
- if __name__ == "__main__":
373
- sys.exit(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
som_metrics.py DELETED
@@ -1,993 +0,0 @@
1
- """som_metrics.py — V6.5-V2-metrics: Métricas de aprendizado e indicadores de
2
- falha para Mapas Auto-Organizáveis (SOM / Redes de Kohonen).
3
-
4
- ============================================================================
5
- MÉTRICAS PRINCIPAIS DE APRENDIZADO
6
- ============================================================================
7
-
8
- 1.1. Erro de Quantização (Quantization Error - QE)
9
- Média das distâncias euclidianas entre cada vetor de entrada e o vetor
10
- de pesos de seu neurônio vencedor (BMU). Mede a resolução ou ajuste fino
11
- do mapa aos dados.
12
-
13
- QE = (1/N) * Σ_i ||x_i - W_BMU(x_i)||₂
14
-
15
- 1.2. Erro Topológico (Topological Error - TE)
16
- Percentual de vetores de entrada cujos primeiro e segundo neurônios
17
- mais próximos (BMU e segunda BMU) NÃO são vizinhos diretos na grade
18
- de saída. Avalia preservação das relações geométricas.
19
-
20
- TE = (1/N) * Σ_i 𝟙[¬adjacent(BMU_1(x_i), BMU_2(x_i))]
21
-
22
- 1.3. Erro de Kaski-Lagus
23
- Combinação ponderada que penaliza tanto a falta de resolução do vetor
24
- de quantização quanto as quebras na continuidade topológica.
25
-
26
- KL = α * QE_norm + β * TE
27
- onde α=0.5, β=0.5 (pesos padrão)
28
-
29
- Variante implementada: KL = QE * (1 + TE) (penaliza QE quando TE é alto)
30
-
31
- 1.4. Variância Explicada (Share of Explained Variance)
32
- Fração da variabilidade total dos dados de entrada que é mapeada e
33
- representada pelos vetores de referência (pesos) dos nós da rede.
34
-
35
- VarExplained = 1 - Var(residual) / Var(total)
36
- onde residual = x_i - W_BMU(x_i)
37
-
38
- ============================================================================
39
- INDICADORES DE NÃO APRENDIZADO OU FALHA
40
- ============================================================================
41
-
42
- 2.1. Colapso Topológico (Topological Collapse)
43
- Ocorre quando todos os vetores de peso convergem para o mesmo ponto
44
- ou para uma linha reta. Indica perda total da dimensionalidade útil.
45
-
46
- Detecção:
47
- - std(weights) por dimensão < threshold (colapso total)
48
- - rank(weights reshaped) < 2 (todos num ponto)
49
- - rank < 3 (todos numa linha)
50
-
51
- 2.2. Taxa de Neurônios Mortos (Dead Neurons)
52
- Percentual de neurônios que NUNCA se tornam BMU para nenhum vetor.
53
-
54
- DeadRate = (n_neurons - n_active_neurons) / n_neurons
55
-
56
- Threshold: DeadRate > 0.5 indica problema.
57
-
58
- 2.3. Estagnação do Erro de Quantização
59
- QE estabiliza em patamar elevado ao longo das épocas. A taxa de
60
- aprendizado decaiu rápido demais antes da fase de ordenação global.
61
-
62
- Detecção: slope(QE) ≈ 0 E QE atual > 0.7 * max(QE histórico)
63
-
64
- 2.4. Cruzamento de Vizinhança (Neighborhood Crossing)
65
- Crescimento repentino ou oscilação crônica do TE nas épocas finais.
66
-
67
- Detecção:
68
- - std(TE_final_5_epochs) > 2 * std(TE_initial_5_epochs) (oscilação)
69
- - TE[-1] > TE[-5] (crescimento no final)
70
-
71
- ============================================================================
72
- AUTOR: V6.5-V2-metrics
73
- ============================================================================
74
- """
75
- from __future__ import annotations
76
-
77
- import math
78
- import logging
79
- from collections import defaultdict, deque
80
- from dataclasses import dataclass, field
81
- from typing import Any, Dict, List, Optional, Tuple
82
-
83
- import torch
84
- import torch.nn.functional as F
85
-
86
- logger = logging.getLogger(__name__)
87
-
88
-
89
- # ============================================================================
90
- # Dataclass para armazenar histórico de métricas
91
- # ============================================================================
92
- @dataclass
93
- class SOMMetricHistory:
94
- """Histórico deslizante de métricas SOM para detecção de estagnação e
95
- cruzamento de vizinhança."""
96
- qe_history: deque = field(default_factory=lambda: deque(maxlen=50))
97
- te_history: deque = field(default_factory=lambda: deque(maxlen=50))
98
- kl_history: deque = field(default_factory=lambda: deque(maxlen=50))
99
- var_explained_history: deque = field(default_factory=lambda: deque(maxlen=50))
100
- dead_neuron_rate_history: deque = field(default_factory=lambda: deque(maxlen=50))
101
- epoch: int = 0
102
-
103
- @staticmethod
104
- def _safe_float(v: Any, default: float = 0.0) -> float:
105
- """Converte para float, substituindo NaN/Inf por default.
106
-
107
- V6.5-V2-metrics-FIX-3: Um único NaN no histórico contamina
108
- permanentemente a detecção de estagnação (regressão linear)
109
- e de cruzamento de vizinhança (média/desvio-padrão). Esta
110
- barreira garante que somente valores finitos entrem no deque.
111
- """
112
- try:
113
- f = float(v)
114
- except (TypeError, ValueError):
115
- return default
116
- if not math.isfinite(f):
117
- return default
118
- return f
119
-
120
- def record(self, metrics: Dict[str, Any]) -> None:
121
- """Registra métricas de uma época (NaN/Inf são substituídos por 0.0).
122
-
123
- Nota: `dead_neuron_rate` pode ser float (valor direto) ou Dict
124
- (saída de compute_all_metrics, com chave 'dead_neuron_rate').
125
- """
126
- self.qe_history.append(self._safe_float(metrics.get("quantization_error", 0.0)))
127
- self.te_history.append(self._safe_float(metrics.get("topological_error", 0.0)))
128
- self.kl_history.append(self._safe_float(metrics.get("kaski_lagus_error", 0.0)))
129
- self.var_explained_history.append(
130
- self._safe_float(metrics.get("explained_variance_share", 0.0))
131
- )
132
- # dead_neuron_rate pode ser float ou Dict
133
- dnr = metrics.get("dead_neuron_rate", 0.0)
134
- if isinstance(dnr, dict):
135
- dnr_val = self._safe_float(dnr.get("dead_neuron_rate", 0.0))
136
- else:
137
- dnr_val = self._safe_float(dnr)
138
- self.dead_neuron_rate_history.append(dnr_val)
139
- self.epoch += 1
140
-
141
- def to_dict(self) -> Dict[str, Any]:
142
- return {
143
- "epoch": int(self.epoch),
144
- "qe_history": list(self.qe_history),
145
- "te_history": list(self.te_history),
146
- "kl_history": list(self.kl_history),
147
- "var_explained_history": list(self.var_explained_history),
148
- "dead_neuron_rate_history": list(self.dead_neuron_rate_history),
149
- }
150
-
151
-
152
- # ============================================================================
153
- # Funções auxiliares
154
- # ============================================================================
155
- def _grid_neighbors_set(
156
- idx: Tuple[int, int, int, int],
157
- grid_shape: Tuple[int, int, int, int],
158
- ) -> set:
159
- """Retorna o conjunto de índices vizinhos diretos (6-connectivity em 4D)
160
- de um neurônio na grade."""
161
- i, j, k, l = idx
162
- I, J, K, L = grid_shape
163
- neighbors = set()
164
- for di, dj, dk, dl in [
165
- (1, 0, 0, 0), (-1, 0, 0, 0),
166
- (0, 1, 0, 0), (0, -1, 0, 0),
167
- (0, 0, 1, 0), (0, 0, -1, 0),
168
- (0, 0, 0, 1), (0, 0, 0, -1),
169
- ]:
170
- ni, nj, nk, nl = i + di, j + dj, k + dk, l + dl
171
- if 0 <= ni < I and 0 <= nj < J and 0 <= nk < K and 0 <= nl < L:
172
- neighbors.add((ni, nj, nk, nl))
173
- return neighbors
174
-
175
-
176
- def _find_bmu_and_second(
177
- x: torch.Tensor, weights: torch.Tensor
178
- ) -> Tuple[Tuple[int, int, int, int], Tuple[int, int, int, int], float, float]:
179
- """Encontra BMU e 2ª BMU para um vetor x.
180
-
181
- Args:
182
- x: tensor [4] — vetor 4D de entrada.
183
- weights: tensor [I, J, K, L, 4] — pesos do SOM.
184
-
185
- Returns:
186
- (bmu_idx, second_bmu_idx, dist_bmu, dist_second)
187
- """
188
- grid_shape = weights.shape[:-1]
189
- flat_w = weights.view(-1, 4) # (I*J*K*L, 4)
190
- diff = flat_w - x.view(1, 4)
191
- dist_sq = torch.sum(diff * diff, dim=-1) # (I*J*K*L,)
192
-
193
- # Top-2 menores distâncias
194
- top2 = torch.topk(dist_sq, k=2, largest=False)
195
- flat_idx_bmu = int(top2.indices[0].item())
196
- flat_idx_2nd = int(top2.indices[1].item())
197
-
198
- # Unravel
199
- L = grid_shape[3]
200
- K = grid_shape[2]
201
- J = grid_shape[1]
202
-
203
- def unravel(flat_idx: int) -> Tuple[int, int, int, int]:
204
- i = flat_idx // (J * K * L)
205
- r = flat_idx % (J * K * L)
206
- j = r // (K * L)
207
- r = r % (K * L)
208
- k = r // L
209
- l = r % L
210
- return (i, j, k, l)
211
-
212
- bmu = unravel(flat_idx_bmu)
213
- second = unravel(flat_idx_2nd)
214
- dist_bmu = float(math.sqrt(max(top2.values[0].item(), 0.0)))
215
- dist_second = float(math.sqrt(max(top2.values[1].item(), 0.0)))
216
- return bmu, second, dist_bmu, dist_second
217
-
218
-
219
- # ============================================================================
220
- # Métricas principais (1.1 - 1.4)
221
- # ============================================================================
222
- def quantization_error(
223
- data: torch.Tensor, weights: torch.Tensor
224
- ) -> float:
225
- """1.1 Erro de Quantização (QE).
226
-
227
- QE = (1/N) * Σ_i ||x_i - W_BMU(x_i)||₂
228
-
229
- Args:
230
- data: tensor [N, 4] — vetores de entrada.
231
- weights: tensor [I, J, K, L, 4] — pesos do SOM.
232
-
233
- Returns:
234
- QE (float). 0.0 se data vazio. NaN/Inf propagado é substituído por 0.0
235
- (V6.5-V2-metrics-FIX-3: agora também captura Inf, não apenas NaN).
236
- """
237
- if data.numel() == 0:
238
- return 0.0
239
- flat_w = weights.view(-1, 4) # (M, 4)
240
- # distância de cada amostra a todos os neurônios
241
- # data: (N, 4), flat_w: (M, 4) -> (N, M)
242
- diff = data.unsqueeze(1) - flat_w.unsqueeze(0)
243
- dist_sq = torch.sum(diff * diff, dim=-1) # (N, M)
244
- min_dist_sq, _ = torch.min(dist_sq, dim=1) # (N,)
245
- # V6.5-V2-metrics-FIX-2: clamp para evitar sqrt de número negativo (float err)
246
- min_dist_sq = torch.clamp(min_dist_sq, min=0.0)
247
- qe = torch.mean(torch.sqrt(min_dist_sq))
248
- qe_val = float(qe.item())
249
- # V6.5-V2-metrics-FIX-3: rejeita tanto NaN quanto Inf
250
- if not math.isfinite(qe_val):
251
- return 0.0
252
- return qe_val
253
-
254
-
255
- def topological_error(
256
- data: torch.Tensor, weights: torch.Tensor
257
- ) -> float:
258
- """1.2 Erro Topológico (TE).
259
-
260
- TE = (1/N) * Σ_i 𝟙[¬adjacent(BMU_1(x_i), BMU_2(x_i))]
261
-
262
- Dois neurônios são adjacentes se differem em exatamente uma coordenada
263
- por ±1 (6-connectivity em 4D).
264
-
265
- Args:
266
- data: tensor [N, 4]
267
- weights: tensor [I, J, K, L, 4]
268
-
269
- Returns:
270
- TE ∈ [0, 1]. 0.0 se data vazio ou se grid tem < 2 neurônios.
271
- """
272
- if data.numel() == 0:
273
- return 0.0
274
- # V6.5-V2-metrics-FIX-3: guard contra grid com < 2 neurônios
275
- # (torch.topk(k=2) levanta RuntimeError se M < 2).
276
- M = weights.shape[0] * weights.shape[1] * weights.shape[2] * weights.shape[3]
277
- if M < 2:
278
- return 0.0
279
- grid_shape = weights.shape[:-1]
280
- flat_w = weights.view(-1, 4)
281
- diff = data.unsqueeze(1) - flat_w.unsqueeze(0)
282
- dist_sq = torch.sum(diff * diff, dim=-1) # (N, M)
283
- # V6.5-V2-metrics-FIX-3: substitui NaN/Inf por +inf antes do topk
284
- # para que neurônios com pesos degenerados não sejam eleitos BMU.
285
- dist_sq = torch.where(torch.isfinite(dist_sq), dist_sq, torch.full_like(dist_sq, float('inf')))
286
-
287
- # Top-2 BMUs para cada amostra
288
- top2 = torch.topk(dist_sq, k=2, largest=False, dim=1)
289
- flat_bmu = top2.indices[:, 0] # (N,)
290
- flat_2nd = top2.indices[:, 1] # (N,)
291
-
292
- # Unravel
293
- L = grid_shape[3]
294
- K = grid_shape[2]
295
- J = grid_shape[1]
296
- I = grid_shape[0]
297
-
298
- def unravel_batch(flat_idx: torch.Tensor) -> torch.Tensor:
299
- """Retorna tensor (N, 4) com (i, j, k, l)."""
300
- i = flat_idx // (J * K * L)
301
- r = flat_idx % (J * K * L)
302
- j = r // (K * L)
303
- r = r % (K * L)
304
- k = r // L
305
- l = r % L
306
- return torch.stack([i, j, k, l], dim=1).long()
307
-
308
- bmu_idx = unravel_batch(flat_bmu) # (N, 4)
309
- second_idx = unravel_batch(flat_2nd) # (N, 4)
310
-
311
- # Adjacência: |Δcoord| soma = 1 (apenas uma coordenada muda por ±1)
312
- delta = (bmu_idx - second_idx).abs() # (N, 4)
313
- is_adjacent = (delta.sum(dim=1) == 1) & (delta.max(dim=1).values == 1)
314
-
315
- te = 1.0 - float(is_adjacent.float().mean().item())
316
- # V6.5-V2-metrics-FIX-3: rejeita NaN/Inf no resultado
317
- if not math.isfinite(te):
318
- return 0.0
319
- return te
320
-
321
-
322
- def kaski_lagus_error(
323
- data: torch.Tensor, weights: torch.Tensor, alpha: float = 0.5
324
- ) -> float:
325
- """1.3 Erro de Kaski-Lagus.
326
-
327
- Combinação ponderada de QE normalizado e TE.
328
-
329
- Variante implementada (Kaski & Lagus, 1999):
330
- KL = α * MQE_norm + (1-α) * TE
331
- onde MQE_norm = QE / mean(||x||) (normalização por escala dos dados).
332
-
333
- Uma variante alternativa multiplica:
334
- KL = QE * (1 + TE)
335
- que penaliza QE quando TE é alto (usada se use_multiplicative=True).
336
-
337
- Args:
338
- data: tensor [N, 4]
339
- weights: tensor [I, J, K, L, 4]
340
- alpha: peso do QE normalizado (default 0.5)
341
-
342
- Returns:
343
- KL (float). 0.0 se data vazio ou se NaN for detectado
344
- (V6.5-V2-metrics-FIX-2: user requirement "investigar QE e KL resultando
345
- em NAN").
346
- """
347
- if data.numel() == 0:
348
- return 0.0
349
- qe = quantization_error(data, weights)
350
- te = topological_error(data, weights)
351
- # V6.5-V2-metrics-FIX-3: normalização canônica por desvio em torno do
352
- # centróide (mean(||x_i - x̄||)), NÃO por mean(||x_i||). A versão antiga
353
- # era sensível a translação dos dados — deslocar todos os vetores por +c
354
- # inflava artificialmente ||x|| e reduzia KL, mesmo com QE/TE inalterados.
355
- centroid = data.mean(dim=0, keepdim=True) # (1, 4)
356
- centered_norm = torch.norm(data - centroid, dim=1) # (N,)
357
- data_norm = float(centered_norm.mean().item())
358
- # V6.5-V2-metrics-FIX-2: se data_norm é NaN ou zero, usa 1.0 como fallback
359
- if not math.isfinite(data_norm) or data_norm < 1e-8:
360
- data_norm = 1.0
361
- qe_norm = qe / max(data_norm, 1e-8)
362
- kl = alpha * qe_norm + (1.0 - alpha) * te
363
- kl_val = float(kl)
364
- # V6.5-V2-metrics-FIX-3: rejeita tanto NaN quanto Inf
365
- if not math.isfinite(kl_val):
366
- return 0.0
367
- return kl_val
368
-
369
-
370
- def explained_variance_share(
371
- data: torch.Tensor, weights: torch.Tensor
372
- ) -> float:
373
- """1.4 Variância Explicada (Share of Explained Variance).
374
-
375
- VarExplained = 1 - Var(residual) / Var(total)
376
- onde residual = x_i - W_BMU(x_i)
377
-
378
- Implementação: computamos a variância total dos dados (soma das variâncias
379
- por dimensão) e a variância dos resíduos. A fração explicada é:
380
-
381
- VE = 1 - Σ_d Var(residual_d) / Σ_d Var(data_d)
382
-
383
- Returns:
384
- VE ∈ [0, 1]. Próximo de 1 = boa representação.
385
- """
386
- if data.numel() == 0 or data.shape[0] < 2:
387
- return 0.0
388
- flat_w = weights.view(-1, 4)
389
- diff = data.unsqueeze(1) - flat_w.unsqueeze(0)
390
- dist_sq = torch.sum(diff * diff, dim=-1) # (N, M)
391
- _, bmu_flat = torch.min(dist_sq, dim=1) # (N,)
392
- bmu_w = flat_w[bmu_flat] # (N, 4)
393
- residual = data - bmu_w # (N, 4)
394
-
395
- # Variância por dimensão (sem viés, ddof=0)
396
- var_data = torch.var(data, dim=0, unbiased=False) # (4,)
397
- var_resid = torch.var(residual, dim=0, unbiased=False) # (4,)
398
-
399
- total_var = float(torch.sum(var_data).item())
400
- resid_var = float(torch.sum(var_resid).item())
401
- # V6.5-V2-metrics-FIX-3: se dados são constantes (var~0) e o SOM os
402
- # representa perfeitamente (resid~0), a variância explicada é 1.0
403
- # (caso degenerado, mas correto). Antes retornava 0.0 erroneamente.
404
- if total_var < 1e-12:
405
- return 1.0 if resid_var < 1e-12 else 0.0
406
- ve = 1.0 - (resid_var / total_var)
407
- ve_val = float(max(0.0, min(1.0, ve)))
408
- # V6.5-V2-metrics-FIX-3: rejeita NaN/Inf
409
- if not math.isfinite(ve_val):
410
- return 0.0
411
- return ve_val
412
-
413
-
414
- # ============================================================================
415
- # Indicadores de falha (2.1 - 2.4)
416
- # ============================================================================
417
- def topological_collapse(weights: torch.Tensor) -> Dict[str, Any]:
418
- """2.1 Colapso Topológico (Topological Collapse).
419
-
420
- Detecta se os pesos colapsaram para um ponto (rank < 1) ou para uma linha
421
- (rank < 2). Usa SVD sobre os pesos reshaped (M, 4).
422
-
423
- Args:
424
- weights: tensor [I, J, K, L, 4]
425
-
426
- Returns:
427
- Dict com:
428
- - collapsed_to_point: bool (todos iguais)
429
- - collapsed_to_line: bool (variação só em 1 direção)
430
- - effective_rank: float (rank efetivo via razão de singular values)
431
- - singular_values: list[float]
432
- - severity: str ("none" | "line" | "point")
433
- """
434
- flat_w = weights.view(-1, 4).clone() # (M, 4)
435
- if flat_w.numel() == 0:
436
- return {"collapsed_to_point": False, "collapsed_to_line": False,
437
- "effective_rank": 0.0, "singular_values": [], "severity": "none"}
438
-
439
- # Centraliza
440
- flat_w_centered = flat_w - flat_w.mean(dim=0, keepdim=True)
441
-
442
- # V6.5-V2-metrics FIX: usa SVD com fallback robusto para matrizes
443
- # singulares/ill-conditioned. Se SVD falhar, usa np.linalg.eigh com
444
- # regularização (adiciona pequeno ruído diagonal).
445
- S_list: List[float] = []
446
- try:
447
- # Tentativa 1: SVD direto (mais estável que eigh)
448
- U, S, V = torch.linalg.svd(flat_w_centered, full_matrices=False)
449
- S_list = [float(s.item()) for s in S]
450
- except Exception:
451
- # Tentativa 2: eigendecomposição da matriz de covariância com regularização
452
- try:
453
- cov = flat_w_centered.t() @ flat_w_centered
454
- # Regularização: adiciona pequeno valor diagonal para estabilizar
455
- n = cov.shape[0]
456
- reg = 1e-6 * float(cov.diag().max().item()) if n > 0 else 1e-6
457
- cov_reg = cov + torch.eye(n) * reg
458
- S_eigh, _ = torch.linalg.eigh(cov_reg)
459
- S_eigh = S_eigh.flip(0) # descending order
460
- # Converte autovalores em "singular values" aproximados (sqrt)
461
- S_list = [float(math.sqrt(max(s.item(), 0.0))) for s in S_eigh]
462
- except Exception:
463
- # Tentativa 3: usa norma de Frobenius como aproximação
464
- s_frob = float(torch.norm(flat_w_centered).item())
465
- S_list = [s_frob, 0.0, 0.0, 0.0]
466
-
467
- if not S_list:
468
- return {"collapsed_to_point": False, "collapsed_to_line": False,
469
- "effective_rank": 0.0, "singular_values": [], "severity": "none"}
470
-
471
- # V6.5-V2-metrics-FIX-3: se SVD retornou NaN/Inf (pesos degenerados),
472
- # marca explicitamente como corrupção por NaN para não mascarar o problema.
473
- if any(not math.isfinite(s) for s in S_list):
474
- return {
475
- "collapsed_to_point": False, "collapsed_to_line": False,
476
- "effective_rank": 0.0, "singular_values": S_list,
477
- "severity": "nan_corrupt",
478
- "error": "SVD returned NaN/Inf singular values (weights contain NaN/Inf)",
479
- }
480
-
481
- s_max = max(S_list[0] if S_list else 0.0, 1e-12)
482
-
483
- # Effective rank: número de singular values > 1% do maior
484
- threshold = 0.01 * s_max
485
- n_significant = sum(1 for s in S_list if s > threshold)
486
- # Effective rank (float, via entropy)
487
- s_norm = [s / s_max for s in S_list]
488
- s_norm = [s for s in s_norm if s > 1e-10]
489
- if s_norm:
490
- p = torch.tensor(s_norm)
491
- p_norm = p / p.sum()
492
- entropy = -float(torch.sum(p_norm * torch.log(p_norm)).item())
493
- effective_rank = math.exp(entropy)
494
- else:
495
- effective_rank = 0.0
496
-
497
- collapsed_to_point = n_significant <= 1 and s_max < 1e-6
498
- collapsed_to_line = n_significant == 1 and s_max >= 1e-6
499
-
500
- if collapsed_to_point:
501
- severity = "point"
502
- elif collapsed_to_line:
503
- severity = "line"
504
- else:
505
- severity = "none"
506
-
507
- return {
508
- "collapsed_to_point": bool(collapsed_to_point),
509
- "collapsed_to_line": bool(collapsed_to_line),
510
- "effective_rank": float(effective_rank),
511
- "singular_values": S_list,
512
- "severity": severity,
513
- }
514
-
515
-
516
- def dead_neuron_rate(
517
- data: torch.Tensor, weights: torch.Tensor
518
- ) -> Dict[str, Any]:
519
- """2.2 Taxa de Neurônios Mortos (Dead Neurons).
520
-
521
- DeadRate = (n_neurons - n_active_neurons) / n_neurons
522
-
523
- Um neurônio é "ativo" se é BMU para pelo menos uma amostra.
524
-
525
- Args:
526
- data: tensor [N, 4]
527
- weights: tensor [I, J, K, L, 4]
528
-
529
- Returns:
530
- Dict com:
531
- - dead_neuron_rate: float ∈ [0, 1]
532
- - n_dead: int
533
- - n_active: int
534
- - n_total: int
535
- - dead_indices: list de (i,j,k,l)
536
- """
537
- n_total = weights.shape[0] * weights.shape[1] * weights.shape[2] * weights.shape[3]
538
- if data.numel() == 0:
539
- return {"dead_neuron_rate": 1.0, "n_dead": n_total, "n_active": 0,
540
- "n_total": n_total, "dead_indices": []}
541
-
542
- flat_w = weights.view(-1, 4)
543
- diff = data.unsqueeze(1) - flat_w.unsqueeze(0)
544
- dist_sq = torch.sum(diff * diff, dim=-1) # (N, M)
545
- # V6.5-V2-metrics-FIX-3: substitui NaN/Inf por +inf para que neurônios
546
- # degenerados não sejam eleitos BMU e não causem IndexError.
547
- dist_sq = torch.where(torch.isfinite(dist_sq), dist_sq, torch.full_like(dist_sq, float('inf')))
548
- _, bmu_flat = torch.min(dist_sq, dim=1) # (N,)
549
- # V6.5-V2-metrics-FIX-3: valida range dos índices antes de indexar
550
- bmu_flat = torch.clamp(bmu_flat, 0, n_total - 1)
551
-
552
- active_mask = torch.zeros(n_total, dtype=torch.bool)
553
- active_mask[bmu_flat] = True
554
- n_active = int(active_mask.sum().item())
555
- n_dead = n_total - n_active
556
-
557
- # Coleta índices mortos
558
- dead_flat = (~active_mask).nonzero(as_tuple=True)[0]
559
- L_dim = weights.shape[3]
560
- K_dim = weights.shape[2]
561
- J_dim = weights.shape[1]
562
- dead_indices = []
563
- for flat_idx in dead_flat.tolist():
564
- i = flat_idx // (J_dim * K_dim * L_dim)
565
- r = flat_idx % (J_dim * K_dim * L_dim)
566
- j = r // (K_dim * L_dim)
567
- r = r % (K_dim * L_dim)
568
- k = r // L_dim
569
- l = r % L_dim
570
- dead_indices.append((i, j, k, l))
571
-
572
- return {
573
- "dead_neuron_rate": float(n_dead / n_total) if n_total > 0 else 0.0,
574
- "n_dead": int(n_dead),
575
- "n_active": int(n_active),
576
- "n_total": int(n_total),
577
- "dead_indices": dead_indices[:50], # limita para não explodir JSON
578
- }
579
-
580
-
581
- def quantization_error_stagnation(
582
- history: SOMMetricHistory,
583
- high_threshold_frac: float = 0.7,
584
- slope_tolerance: float = 1e-4,
585
- window_size: int = 5,
586
- ) -> Dict[str, Any]:
587
- """2.3 Estagnação do Erro de Quantização.
588
-
589
- Detecta se o QE estabilizou em patamar elevado:
590
- - |slope(QE)| < slope_tolerance (estável)
591
- - QE_atual > high_threshold_frac * max(QE_history) (alto)
592
-
593
- Args:
594
- history: histórico de métricas SOM.
595
- high_threshold_frac: fração do QE máximo para considerar "alto".
596
- slope_tolerance: tolerância de slope para considerar "estável".
597
- window_size: nº de épocas recentes para regressão linear.
598
-
599
- Returns:
600
- Dict com:
601
- - is_stagnant: bool
602
- - current_qe: float
603
- - max_qe: float
604
- - slope: float
605
- - severity: str ("none" | "mild" | "severe")
606
- """
607
- qe_list = list(history.qe_history)
608
- if len(qe_list) < window_size + 2:
609
- return {"is_stagnant": False, "current_qe": 0.0, "max_qe": 0.0,
610
- "slope": 0.0, "severity": "none", "n_epochs": len(qe_list)}
611
-
612
- # Regressão linear sobre as últimas window_size épocas
613
- recent = qe_list[-window_size:]
614
- n = len(recent)
615
- x_mean = (n - 1) / 2.0
616
- y_mean = sum(recent) / n
617
- num = sum((i - x_mean) * (y - y_mean) for i, y in enumerate(recent))
618
- den = sum((i - x_mean) ** 2 for i in range(n))
619
- slope = num / den if den > 0 else 0.0
620
-
621
- current_qe = float(qe_list[-1])
622
- max_qe = float(max(qe_list))
623
- # V6.5-V2-metrics-FIX-3: tolerância RELATIVA à magnitude do QE,
624
- # não absoluta. Para QE~0.01, slope_tolerance=1e-4 representaria
625
- # 1% por época (grande); para QE~100, seria negligenciável.
626
- rel_tol = slope_tolerance * max(1.0, max_qe)
627
- is_high = current_qe > high_threshold_frac * max_qe
628
- is_stable = abs(slope) < rel_tol
629
-
630
- is_stagnant = is_stable and is_high
631
-
632
- if is_stagnant:
633
- if current_qe > 0.9 * max_qe:
634
- severity = "severe"
635
- else:
636
- severity = "mild"
637
- else:
638
- severity = "none"
639
-
640
- return {
641
- "is_stagnant": bool(is_stagnant),
642
- "current_qe": current_qe,
643
- "max_qe": max_qe,
644
- "slope": float(slope),
645
- "severity": severity,
646
- "n_epochs": len(qe_list),
647
- }
648
-
649
-
650
- def neighborhood_crossing(
651
- history: SOMMetricHistory,
652
- initial_window: int = 5,
653
- final_window: int = 5,
654
- growth_threshold: float = 1.5,
655
- ) -> Dict[str, Any]:
656
- """2.4 Cruzamento de Vizinhança (Neighborhood Crossing).
657
-
658
- Detecta crescimento repentino ou oscilação crônica do TE nas épocas
659
- finais:
660
- - std(TE_final) > growth_threshold * std(TE_initial) (oscilação cresceu)
661
- - TE[-1] > TE[-5] (crescimento no final)
662
-
663
- Args:
664
- history: histórico de métricas SOM.
665
- initial_window: nº de épocas iniciais para baseline.
666
- final_window: nº de épocas finais para comparação.
667
- growth_threshold: razão de std para considerar "crescimento crônico".
668
-
669
- Returns:
670
- Dict com:
671
- - detected: bool
672
- - te_initial_mean: float
673
- - te_final_mean: float
674
- - te_initial_std: float
675
- - te_final_std: float
676
- - std_ratio: float
677
- - is_oscillating: bool
678
- - is_growing: bool
679
- - severity: str ("none" | "mild" | "severe")
680
- """
681
- te_list = list(history.te_history)
682
- if len(te_list) < initial_window + final_window:
683
- return {"detected": False, "te_initial_mean": 0.0, "te_final_mean": 0.0,
684
- "te_initial_std": 0.0, "te_final_std": 0.0, "std_ratio": 0.0,
685
- "is_oscillating": False, "is_growing": False, "severity": "none",
686
- "n_epochs": len(te_list)}
687
-
688
- initial = te_list[:initial_window]
689
- final = te_list[-final_window:]
690
-
691
- # V6.5-V2-metrics-FIX-3: filtra NaN/Inf (defesa em profundidade — o
692
- # SOMMetricHistory.record já deveria ter feito isso, mas chamadas
693
- # diretas a neighborhood_crossing podem receber histórico corrupto).
694
- initial = [v for v in initial if math.isfinite(v)]
695
- final = [v for v in final if math.isfinite(v)]
696
- if len(initial) < 2 or len(final) < 2:
697
- return {"detected": False, "te_initial_mean": 0.0, "te_final_mean": 0.0,
698
- "te_initial_std": 0.0, "te_final_std": 0.0, "std_ratio": 0.0,
699
- "is_oscillating": False, "is_growing": False, "severity": "none",
700
- "n_epochs": len(te_list)}
701
-
702
- init_mean = sum(initial) / len(initial)
703
- final_mean = sum(final) / len(final)
704
- init_var = sum((x - init_mean) ** 2 for x in initial) / len(initial)
705
- final_var = sum((x - final_mean) ** 2 for x in final) / len(final)
706
- init_std = math.sqrt(init_var)
707
- final_std = math.sqrt(final_var)
708
-
709
- std_ratio = final_std / max(init_std, 1e-8)
710
- is_oscillating = std_ratio > growth_threshold
711
- is_growing = final_mean > init_mean and (final_mean - init_mean) > 0.05
712
-
713
- detected = is_oscillating or is_growing
714
-
715
- if detected:
716
- if std_ratio > 2.0 * growth_threshold or is_growing:
717
- severity = "severe"
718
- else:
719
- severity = "mild"
720
- else:
721
- severity = "none"
722
-
723
- return {
724
- "detected": bool(detected),
725
- "te_initial_mean": float(init_mean),
726
- "te_final_mean": float(final_mean),
727
- "te_initial_std": float(init_std),
728
- "te_final_std": float(final_std),
729
- "std_ratio": float(std_ratio),
730
- "is_oscillating": bool(is_oscillating),
731
- "is_growing": bool(is_growing),
732
- "severity": severity,
733
- "n_epochs": len(te_list),
734
- }
735
-
736
-
737
- # ============================================================================
738
- # Função agregadora: compute_all_metrics
739
- # ============================================================================
740
- def compute_all_metrics(
741
- data: torch.Tensor,
742
- weights: torch.Tensor,
743
- history: Optional[SOMMetricHistory] = None,
744
- ) -> Dict[str, Any]:
745
- """Computa todas as métricas SOM de uma vez.
746
-
747
- Args:
748
- data: tensor [N, 4] — buffer de vetores 4D.
749
- weights: tensor [I, J, K, L, 4] — pesos do SOM.
750
- history: histórico de métricas (opcional, para estagnação e cruzamento).
751
-
752
- Returns:
753
- Dict com:
754
- - quantization_error: float
755
- - topological_error: float
756
- - kaski_lagus_error: float
757
- - explained_variance_share: float
758
- - topological_collapse: Dict
759
- - dead_neuron_rate: Dict
760
- - quantization_error_stagnation: Dict (se history fornecido)
761
- - neighborhood_crossing: Dict (se history fornecido)
762
- - overall_health: str ("healthy" | "warning" | "critical")
763
- - failure_indicators: list[str]
764
- """
765
- # V6.5-V2-metrics FIX: wrap entire computation in try/except para evitar
766
- # crashes fatais quando o SOM tem pesos degenerados (ex: todos iguais
767
- # após muito treinamento sem diversidade). Em caso de erro, retorna
768
- # métricas safe-default em vez de crashar o treino.
769
-
770
- # V6.5-V2-metrics-FIX-2 (user requirement: "investigar QE e KL resultando
771
- # em NAN"): detecção EXPLÍCITA de NaN/Inf nos tensores de entrada ANTES
772
- # de computar as métricas. Se os pesos do SOM contêm NaN (devido a
773
- # gradientes explosivos durante train_hypotheses ou apply_best_delta),
774
- # TODAS as métricas (QE, KL, etc.) seriam NaN, propagando o erro para
775
- # o histórico e quebrando a detecção de estagnação/cruzamento.
776
- # Esta barreira inicial retorna safe-defaults imediatamente quando
777
- # NaN/Inf é detectado, evitando contaminação do histórico.
778
- try:
779
- if data is not None and data.numel() > 0:
780
- if bool(torch.isnan(data).any().item()) or bool(torch.isinf(data).any().item()):
781
- n_nan = int(torch.isnan(data).sum().item())
782
- n_inf = int(torch.isinf(data).sum().item())
783
- logger.warning(
784
- f"[som_metrics] NaN/Inf detected in INPUT DATA: "
785
- f"{n_nan} NaN, {n_inf} Inf out of {data.numel()} elements. "
786
- f"Returning safe-default metrics (skipping computation)."
787
- )
788
- return _nan_safe_metrics(
789
- reason=f"nan_in_data (nan={n_nan}, inf={n_inf})",
790
- data_shape=tuple(data.shape),
791
- weights_shape=tuple(weights.shape) if weights is not None else None,
792
- )
793
- if weights is not None and weights.numel() > 0:
794
- if bool(torch.isnan(weights).any().item()) or bool(torch.isinf(weights).any().item()):
795
- n_nan = int(torch.isnan(weights).sum().item())
796
- n_inf = int(torch.isinf(weights).sum().item())
797
- logger.warning(
798
- f"[som_metrics] NaN/Inf detected in SOM WEIGHTS: "
799
- f"{n_nan} NaN, {n_inf} Inf out of {weights.numel()} elements. "
800
- f"Returning safe-default metrics (skipping computation). "
801
- f"This usually indicates exploding gradients in "
802
- f"train_hypotheses() or apply_best_delta_and_consolidate()."
803
- )
804
- return _nan_safe_metrics(
805
- reason=f"nan_in_weights (nan={n_nan}, inf={n_inf})",
806
- data_shape=tuple(data.shape) if data is not None else None,
807
- weights_shape=tuple(weights.shape),
808
- )
809
- except Exception as nan_check_err:
810
- logger.warning(
811
- f"[som_metrics] NaN pre-check failed (proceeding to compute): {nan_check_err}"
812
- )
813
-
814
- try:
815
- result = _compute_all_metrics_impl(data, weights, history)
816
- # V6.5-V2-metrics-FIX-3: pós-computação, verifica TODAS as métricas
817
- # escalares por NaN/Inf (não apenas QE/KL). Substitui por 0.0 e marca
818
- # para que o histórico não seja contaminado.
819
- _SCALAR_METRIC_KEYS = [
820
- "quantization_error", "topological_error", "kaski_lagus_error",
821
- "explained_variance_share",
822
- ]
823
- any_nan = False
824
- for k in _SCALAR_METRIC_KEYS:
825
- v = result.get(k, 0.0)
826
- if isinstance(v, float) and not math.isfinite(v):
827
- logger.warning(
828
- f"[som_metrics] {k} computed as NaN/Inf ({v}) — replacing "
829
- f"with 0.0. Investigate train_hypotheses or apply_best_delta "
830
- f"for gradient explosion."
831
- )
832
- result[k] = 0.0
833
- result[f"{k}_was_nan"] = True
834
- any_nan = True
835
- # V6.5-V2-metrics-FIX-3: também verifica sub-dicts de collapse/dead
836
- # para severity='nan_corrupt' e propaga como failure_indicator.
837
- if result.get("topological_collapse", {}).get("severity") == "nan_corrupt":
838
- any_nan = True
839
- if any_nan and "failure_indicators" in result:
840
- result["failure_indicators"].append("post_compute_nan_replaced")
841
- result["overall_health"] = "critical"
842
- result["n_failure_indicators"] = len(result["failure_indicators"])
843
- return result
844
- except Exception as e:
845
- logger.warning(
846
- f"[som_metrics] compute_all_metrics failed (using safe defaults): {e}"
847
- )
848
- return _nan_safe_metrics(reason=f"compute_error: {str(e)[:200]}", data_shape=None, weights_shape=None)
849
-
850
-
851
- def _nan_safe_metrics(
852
- reason: str,
853
- data_shape: Optional[Tuple[int, ...]] = None,
854
- weights_shape: Optional[Tuple[int, ...]] = None,
855
- ) -> Dict[str, Any]:
856
- """V6.5-V2-metrics-FIX-2 — Retorna métricas safe-default quando NaN é detectado.
857
-
858
- User requirement: "Aprimorar a FASE2 PUNITIVA investigar QE e KL resultando em NAN".
859
-
860
- Este helper centraliza a resposta a NaN/Inf em qualquer ponto do pipeline
861
- de métricas, garantindo que:
862
- 1. O treino NÃO crashe.
863
- 2. O histórico de métricas (SOMMetricHistory) NÃO seja contaminado com NaN
864
- (o que quebraria detecção de estagnação e cruzamento de vizinhança).
865
- 3. O log indique claramente a fonte do NaN (data vs weights vs compute_error).
866
- 4. failure_indicators registre o evento para análise pós-treino.
867
- """
868
- return {
869
- "quantization_error": 0.0,
870
- "topological_error": 0.0,
871
- "kaski_lagus_error": 0.0,
872
- "explained_variance_share": 0.0,
873
- "topological_collapse": {
874
- "collapsed_to_point": False, "collapsed_to_line": False,
875
- "effective_rank": 0.0, "singular_values": [],
876
- "severity": "none", "error": reason,
877
- },
878
- "dead_neuron_rate": {
879
- "dead_neuron_rate": 1.0, "n_dead": 0, "n_active": 0,
880
- "n_total": 0, "dead_indices": [], "error": reason,
881
- },
882
- "qe_stagnation": {
883
- "is_stagnant": False, "current_qe": 0.0, "max_qe": 0.0,
884
- "slope": 0.0, "severity": "none", "n_epochs": 0,
885
- },
886
- "neighborhood_crossing": {
887
- "detected": False, "te_initial_mean": 0.0, "te_final_mean": 0.0,
888
- "te_initial_std": 0.0, "te_final_std": 0.0, "std_ratio": 0.0,
889
- "is_oscillating": False, "is_growing": False, "severity": "none",
890
- "n_epochs": 0,
891
- },
892
- "overall_health": "critical",
893
- "failure_indicators": [f"nan_detected: {reason[:120]}"],
894
- "n_failure_indicators": 1,
895
- "nan_detected": True,
896
- "nan_reason": reason,
897
- "data_shape": list(data_shape) if data_shape else None,
898
- "weights_shape": list(weights_shape) if weights_shape else None,
899
- }
900
-
901
-
902
- def _compute_all_metrics_impl(
903
- data: torch.Tensor,
904
- weights: torch.Tensor,
905
- history: Optional[SOMMetricHistory] = None,
906
- ) -> Dict[str, Any]:
907
- """Implementação interna de compute_all_metrics (sem try/except wrapper)."""
908
- metrics: Dict[str, Any] = {}
909
-
910
- # 1.1 - 1.4: Métricas principais
911
- metrics["quantization_error"] = quantization_error(data, weights)
912
- metrics["topological_error"] = topological_error(data, weights)
913
- metrics["kaski_lagus_error"] = kaski_lagus_error(data, weights)
914
- metrics["explained_variance_share"] = explained_variance_share(data, weights)
915
-
916
- # 2.1: Colapso topológico
917
- collapse = topological_collapse(weights)
918
- metrics["topological_collapse"] = collapse
919
-
920
- # 2.2: Dead neurons
921
- dead = dead_neuron_rate(data, weights)
922
- metrics["dead_neuron_rate"] = dead
923
-
924
- # 2.3: Estagnação do QE (requer histórico)
925
- if history is not None and len(history.qe_history) > 5:
926
- metrics["qe_stagnation"] = quantization_error_stagnation(history)
927
- else:
928
- metrics["qe_stagnation"] = {
929
- "is_stagnant": False, "current_qe": metrics["quantization_error"],
930
- "max_qe": metrics["quantization_error"], "slope": 0.0,
931
- "severity": "none", "n_epochs": 0,
932
- }
933
-
934
- # 2.4: Cruzamento de vizinhança (requer histórico)
935
- if history is not None and len(history.te_history) > 10:
936
- metrics["neighborhood_crossing"] = neighborhood_crossing(history)
937
- else:
938
- metrics["neighborhood_crossing"] = {
939
- "detected": False, "te_initial_mean": 0.0, "te_final_mean": 0.0,
940
- "te_initial_std": 0.0, "te_final_std": 0.0, "std_ratio": 0.0,
941
- "is_oscillating": False, "is_growing": False, "severity": "none",
942
- "n_epochs": 0,
943
- }
944
-
945
- # Avaliação de saúde geral
946
- failure_indicators: List[str] = []
947
- if collapse["collapsed_to_point"]:
948
- failure_indicators.append("topological_collapse_point")
949
- elif collapse["collapsed_to_line"]:
950
- failure_indicators.append("topological_collapse_line")
951
- if dead["dead_neuron_rate"] > 0.5:
952
- failure_indicators.append(f"dead_neuron_rate_high_{dead['dead_neuron_rate']:.2f}")
953
- if metrics["qe_stagnation"]["is_stagnant"]:
954
- failure_indicators.append(f"qe_stagnant_{metrics['qe_stagnation']['severity']}")
955
- if metrics["neighborhood_crossing"]["detected"]:
956
- failure_indicators.append(
957
- f"neighborhood_crossing_{metrics['neighborhood_crossing']['severity']}"
958
- )
959
- if metrics["explained_variance_share"] < 0.3:
960
- failure_indicators.append(
961
- f"low_explained_variance_{metrics['explained_variance_share']:.2f}"
962
- )
963
- if metrics["topological_error"] > 0.5:
964
- failure_indicators.append(
965
- f"high_topological_error_{metrics['topological_error']:.2f}"
966
- )
967
-
968
- if len(failure_indicators) >= 2:
969
- overall_health = "critical"
970
- elif len(failure_indicators) == 1:
971
- overall_health = "warning"
972
- else:
973
- overall_health = "healthy"
974
-
975
- metrics["failure_indicators"] = failure_indicators
976
- metrics["overall_health"] = overall_health
977
- metrics["n_failure_indicators"] = len(failure_indicators)
978
-
979
- return metrics
980
-
981
-
982
- __all__ = [
983
- "SOMMetricHistory",
984
- "quantization_error",
985
- "topological_error",
986
- "kaski_lagus_error",
987
- "explained_variance_share",
988
- "topological_collapse",
989
- "dead_neuron_rate",
990
- "quantization_error_stagnation",
991
- "neighborhood_crossing",
992
- "compute_all_metrics",
993
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
streaming_datasets.py DELETED
@@ -1,995 +0,0 @@
1
- """streaming_datasets_v13_9.py — Streaming dataset loader for v13.9.1 training.
2
-
3
- Carrega os 9 datasets especificados pelo usuário via streaming (IterableDataset),
4
- um por vez, exaustivamente dentro do limite max_samples_per_dataset.
5
-
6
- Datasets:
7
- 1. CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1
8
- 2. Madras1/corpus-ptbr-v2
9
- 3. rhaymison/multmodal_175k_portuguese
10
- 4. TucanoBR/GigaVerbo
11
- 5. nvidia/OpenMathReasoning
12
- 6. MathLLMs/MathVision
13
- 7. nvidia/OpenMathInstruct-2
14
- 8. dominguesm/restore-punctuation-ptbr-dataset
15
- 9. carolina-c4ai/corpus-carolina
16
-
17
- Memory-efficient: streaming=True, no full materialization.
18
- Returns ProcessedSample with raw_text only (tokenizer handles encoding).
19
- """
20
- from __future__ import annotations
21
-
22
- import logging
23
- import os
24
- import time
25
- import traceback
26
- from dataclasses import dataclass, field
27
- from typing import Any, Dict, Iterator, List, Optional, Tuple
28
-
29
- import torch
30
-
31
- logger = logging.getLogger(__name__)
32
-
33
- # Datasets V13.9.1 — exatamente os 9 especificados pelo usuário
34
- # V6.5-final: adicionado dominguesm/Canarim-Instruct-PTBR-Dataset
35
- # V6.5-7ds: adicionados adalbertojunior/punctuation-ptbr,
36
- # iara-project/news-articles-ptbr-dataset, manoela/noticias_ptbr
37
- # V6.5-V2: adicionado BrunoN-Dev/corpus-ptbr-v1 como 8º dataset de CONHECIMENTO
38
- # e usado como dataset de TREINAMENTO COM PUNIÇÃO
39
- DEFAULT_DATASETS = [
40
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
41
- "Madras1/corpus-ptbr-v2",
42
- "rhaymison/multmodal_175k_portuguese",
43
- "TucanoBR/GigaVerbo",
44
- "nvidia/OpenMathReasoning",
45
- "MathLLMs/MathVision",
46
- "nvidia/OpenMathInstruct-2",
47
- "dominguesm/restore-punctuation-ptbr-dataset",
48
- "carolina-c4ai/corpus-carolina",
49
- "dominguesm/Canarim-Instruct-PTBR-Dataset",
50
- "adalbertojunior/punctuation-ptbr",
51
- "iara-project/news-articles-ptbr-dataset",
52
- "manoela/noticias_ptbr",
53
- "BrunoN-Dev/corpus-ptbr-v1",
54
- ]
55
-
56
- # V6.5-V2 — Sequência de 8 datasets para a fase CONHECIMENTO (na ordem exata
57
- # especificada pelo usuário). Meta mínima: 8000 samples ou mais.
58
- CONHECIMENTO_DATASETS_V2 = [
59
- "dominguesm/restore-punctuation-ptbr-dataset",
60
- "carolina-c4ai/corpus-carolina",
61
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
62
- "dominguesm/Canarim-Instruct-PTBR-Dataset",
63
- "adalbertojunior/punctuation-ptbr",
64
- "iara-project/news-articles-ptbr-dataset",
65
- "manoela/noticias_ptbr",
66
- "BrunoN-Dev/corpus-ptbr-v1",
67
- ]
68
-
69
- # V6.5-V2 — Dataset para TREINAMENTO COM PUNIÇÃO (500 samples).
70
- # O usuário especificou: "dataset para TREINAMENTO COM PUNIÇÃO ATIVA
71
- # 'BrunoN-Dev/corpus-ptbr-v1'".
72
- PUNICAO_DATASET_V2 = "BrunoN-Dev/corpus-ptbr-v1"
73
-
74
- # Dataset format descriptors — Lista priorizada de campos de texto
75
- DATASET_FORMATS: Dict[str, Dict[str, Any]] = {
76
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": {
77
- "type": "chat",
78
- "text_fields": ["conversa", "text", "content", "conversation", "messages"],
79
- "label_fields": [],
80
- "split": "train",
81
- "config": None,
82
- },
83
- "Madras1/corpus-ptbr-v2": {
84
- "type": "text",
85
- "text_fields": ["text", "content", "document", "body"],
86
- "label_fields": [],
87
- "split": "train",
88
- "config": None,
89
- },
90
- "rhaymison/multmodal_175k_portuguese": {
91
- "type": "multimodal",
92
- "text_fields": ["description", "text", "question", "prompt", "instruction", "input"],
93
- "image_fields": ["image", "image_url"],
94
- "label_fields": ["answer", "response", "output"],
95
- "split": "train",
96
- "config": None,
97
- },
98
- "TucanoBR/GigaVerbo": {
99
- "type": "text",
100
- "text_fields": ["text", "content", "document", "body"],
101
- "label_fields": [],
102
- "split": "train",
103
- "config": None,
104
- },
105
- "nvidia/OpenMathReasoning": {
106
- "type": "math",
107
- "text_fields": ["problem", "question", "input", "prompt"],
108
- "label_fields": ["solution", "answer", "output", "response"],
109
- # BUG FIX: OpenMathReasoning has splits ['cot', 'tir', 'genselect', 'additional_problems']
110
- "split": "cot", # Use 'cot' (chain-of-thought) as primary split
111
- "config": None,
112
- },
113
- "MathLLMs/MathVision": {
114
- "type": "math_multimodal",
115
- "text_fields": ["question", "problem", "text", "query"],
116
- "image_fields": ["image", "image_url"],
117
- "label_fields": ["answer", "solution", "response"],
118
- # BUG FIX: MathVision has only 'test' and 'testmini' splits (no train)
119
- "split": "test",
120
- "config": None,
121
- },
122
- "nvidia/OpenMathInstruct-2": {
123
- "type": "math",
124
- "text_fields": ["problem", "question", "input", "prompt"],
125
- # V3 FIX: campos reais do dataset são generated_solution e expected_answer
126
- "label_fields": ["generated_solution", "expected_answer", "solution", "answer", "output", "response"],
127
- "split": "train",
128
- "config": None,
129
- },
130
- "dominguesm/restore-punctuation-ptbr-dataset": {
131
- "type": "punctuation",
132
- "text_fields": ["text", "original", "unpunctuated", "input"],
133
- "label_fields": ["punctuated", "restored", "target", "output"],
134
- "split": "train",
135
- "config": None,
136
- },
137
- "carolina-c4ai/corpus-carolina": {
138
- "type": "text",
139
- "text_fields": ["text", "content", "document", "body", "xml"],
140
- "label_fields": [],
141
- "split": "train",
142
- "config": None,
143
- # V13.9.2-carolina: dataset original usa script Python (não suportado em
144
- # datasets 5.0+). Workaround: stream_xml_gz direto via lxml.iterparse,
145
- # sem usar o script Python. Implementado em _stream_carolina_direct().
146
- },
147
- # ── V13.9.2-finetune-v2: novos datasets PT-BR ───────────────────────────
148
- # Adicionados para fine-tuning contínuo do modelo v13.9.2 (preserva
149
- # arquitetura e parâmetros). Nenhuma mudança estrutural — apenas novos
150
- # descritores de formato para que stream_dataset() reconheça os datasets.
151
- #
152
- # V13.9.2-finetune-v3: padronização para o formato unificado
153
- # "### Instruction:\n...\n\n### Response:\n..." conforme requisitado pelo
154
- # usuário. Apenas os datasets com estrutura instruction/response (orion,
155
- # cnmoro) usam o template; strak2005/bratao continuam como texto puro
156
- # (corpus sem estrutura de instrução). Nenhuma mudança nos 9 datasets
157
- # base — retrocompatibilidade total.
158
- "orion-research/translations-en_US-pt_BR": {
159
- "type": "translation",
160
- # string = EN (instruction), string_translation = PT-BR (response).
161
- # V13.9.2-finetune-v3: separa instruction/response para o template
162
- # unificado em vez de concatenar como texto único.
163
- "text_fields": ["string"],
164
- "label_fields": ["string_translation"],
165
- "split": "train",
166
- "config": None,
167
- "format_template": "instruction_response",
168
- "instruction_prefix": "Translate the following text to Portuguese:",
169
- },
170
- "cnmoro/Instruct-PTBR-10M": {
171
- "type": "instruct",
172
- # NB: campos em MAIÚSCULAS no schema do dataset
173
- # V13.9.2-finetune-v3: INSTRUCTION -> instruction, RESPONSE -> response
174
- # via template unificado.
175
- "text_fields": ["INSTRUCTION"],
176
- "label_fields": ["RESPONSE"],
177
- "split": "train",
178
- "config": None,
179
- "format_template": "instruction_response",
180
- # V13.9.2-finetune-v2: dataset é um único parquet de 10 GB — streaming
181
- # via datasets.load_dataset() é extremamente lento para materializar
182
- # a primeira amostra. Fallback via HF datasets-server rows API (HTTP),
183
- # que retorna batches de 100 rows rapidamente. Implementado em
184
- # _stream_via_rows_api().
185
- "loader": "rows_api",
186
- },
187
- "strak2005/corpus-ptbr-v1": {
188
- "type": "text",
189
- "text_fields": ["text", "content"],
190
- "label_fields": [],
191
- "split": "train",
192
- "config": None,
193
- # Fallback: se strak2005 cair, tenta bratao (mirror idêntico)
194
- "fallback": "bratao/corpus-ptbr-v1",
195
- # V13.9.2-finetune-v2: dataset tem 18 shards parquet de ~1GB cada.
196
- # Streaming via datasets.load_dataset() não materializa primeira
197
- # amostra em tempo aceitável. Fallback: baixa 1 shard localmente e
198
- # itera com pyarrow. Implementado em _stream_via_parquet_first_shard().
199
- "loader": "parquet_first_shard",
200
- },
201
- "bratao/corpus-ptbr-v1": {
202
- "type": "text",
203
- "text_fields": ["text", "content"],
204
- "label_fields": [],
205
- "split": "train",
206
- "config": None,
207
- "loader": "parquet_first_shard",
208
- },
209
- # ── V6.5: novos datasets para esgotar ────────────────────────────────
210
- # User requirement: "esgotar 'dominguesm/restore-punctuation-ptbr-dataset'
211
- # e 'carolina-c4ai/corpus-carolina' e 'nvidia/OpenMathInstruct-2' e
212
- # 'nvidia/OpenMathReasoning' e 'CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1'
213
- # e 'Dexavator/English-PTBR'"
214
- #
215
- # Dexavator/English-PTBR: dataset de tradução EN->PT-BR.
216
- # Estrutura típica: {"english": "...", "portuguese": "..."} ou
217
- # {"en": "...", "pt": "..."}.
218
- "Dexavator/English-PTBR": {
219
- "type": "translation",
220
- "text_fields": ["english", "en", "text", "source"],
221
- "label_fields": ["portuguese", "pt", "target", "translation"],
222
- "split": "train",
223
- "config": None,
224
- "format_template": "instruction_response",
225
- "instruction_prefix": "Translate the following text to Portuguese:",
226
- },
227
- # ── V6.5-final: Canarim-Instruct-PTBR-Dataset ────────────────────────
228
- # User requirement: "esgotar 'dominguesm/Canarim-Instruct-PTBR-Dataset'"
229
- # Canarim-Instruct: dataset PT-BR de instruções (~430k samples).
230
- # Estrutura típica: {"instruction": "...", "input": "...", "output": "..."}
231
- # ou {"text": "...", "conversation": [{"role": "user", "content": "..."}, ...]}
232
- "dominguesm/Canarim-Instruct-PTBR-Dataset": {
233
- "type": "instruct",
234
- "text_fields": ["instruction", "input", "text", "prompt", "question"],
235
- "label_fields": ["output", "response", "answer"],
236
- "split": "train",
237
- "config": None,
238
- "format_template": "instruction_response",
239
- "instruction_prefix": "Instrução:",
240
- },
241
- # ── V6.5-7ds: novos 3 datasets PT-BR ─────────────────────────────────
242
- # User requirement (latest): "streaming até esgotar nesta sequência
243
- # 'dominguesm/restore-punctuation-ptbr-dataset' e
244
- # 'carolina-c4ai/corpus-carolina' e
245
- # 'CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1' e
246
- # 'dominguesm/Canarim-Instruct-PTBR-Dataset' e
247
- # 'adalbertojunior/punctuation-ptbr' e
248
- # 'iara-project/news-articles-ptbr-dataset' e
249
- # 'manoela/noticias_ptbr'"
250
- #
251
- # adalbertojunior/punctuation-ptbr:
252
- # Dataset de restauração de pontuação PT-BR. Schema:
253
- # {id: str, tokens: list[str], pos_tags, chunk_tags, ner_tags}
254
- # O campo "tokens" é uma lista de palavras (sem pontuação). Precisamos
255
- # fazer join com espaços para obter texto bruto. Como o dataset usa
256
- # script Python (datasets 5.0+ não suporta), usamos rows_api loader.
257
- # Splits: train/validation/test com config "punctuation-ptbr".
258
- "adalbertojunior/punctuation-ptbr": {
259
- "type": "punctuation_tokens",
260
- "text_fields": ["tokens"], # list[str] — join com espaços
261
- "label_fields": [],
262
- "split": "train",
263
- "config": "punctuation-ptbr", # necessário para rows_api
264
- "loader": "rows_api",
265
- "join_tokens": True, # flag especial para _normalize_sample
266
- },
267
- # iara-project/news-articles-ptbr-dataset:
268
- # Dataset de notícias PT-BR da Folha de S.Paulo (via IARA project).
269
- # Schema: {title, text, date, category, category_natural_language, link}
270
- # Streaming normal via parquet — primeira amostra materializa rápido.
271
- # "text" é o corpo da notícia, "title" é o título. Concatenamos ambos
272
- # via format_template="title_text_concat" para enriquecer contexto.
273
- # O campo "category" é usado como label (categoria da notícia).
274
- "iara-project/news-articles-ptbr-dataset": {
275
- "type": "news",
276
- # text_fields em ordem de prioridade: "text" (corpo) primeiro
277
- "text_fields": ["text", "title", "content", "body"],
278
- "label_fields": ["category", "category_natural_language", "title"],
279
- "split": "train",
280
- "config": None,
281
- # V6.5-7ds: title_text_concat usa title como label (prefixo)
282
- # e text como corpo. Aqui label_fields pega "category" primeiro
283
- # para dar contexto temático.
284
- "format_template": "title_text_concat",
285
- },
286
- # manoela/noticias_ptbr:
287
- # Mirror do iara-project/news-articles-ptbr-dataset (mesmo parquet,
288
- # mesmo schema). Streaming normal via parquet.
289
- "manoela/noticias_ptbr": {
290
- "type": "news",
291
- "text_fields": ["text", "title", "content", "body"],
292
- "label_fields": ["category", "category_natural_language", "title"],
293
- "split": "train",
294
- "config": None,
295
- "format_template": "title_text_concat",
296
- },
297
- # ── V6.5-V2: BrunoN-Dev/corpus-ptbr-v1 ───────────────────────────────
298
- # User requirement: "dataset para TREINAMENTO COM PUNIÇÃO ATIVA
299
- # 'BrunoN-Dev/corpus-ptbr-v1'" e o 8º dataset de CONHECIMENTO.
300
- #
301
- # BrunoN-Dev/corpus-ptbr-v1: corpus PT-BR genérico com 18 shards parquet
302
- # (~1GB cada). Schema: {"text": "...", "meta": "..."}.
303
- # Streaming via datasets.load_dataset(streaming=True) é lento para
304
- # materializar a primeira amostra — usamos o loader parquet_first_shard
305
- # (baixa apenas o primeiro shard e itera localmente com pyarrow).
306
- # Sem label explícita — usamos hash do texto (paridade do nº de palavras)
307
- # para gerar label binário (0/1) — não é dado sintético, é derivação
308
- # algorítmica do conteúdo real do dataset.
309
- "BrunoN-Dev/corpus-ptbr-v1": {
310
- "type": "text",
311
- "text_fields": ["text", "content", "body", "document"],
312
- "label_fields": [],
313
- "split": "train",
314
- "config": None,
315
- "loader": "parquet_first_shard",
316
- # V6.5-V2: gera label binário determinístico via hash do texto
317
- # (paridade do número de palavras) — não é dado sintético, é
318
- # derivação algorítmica do conteúdo real do dataset.
319
- "label_strategy": "hash_parity",
320
- },
321
- }
322
-
323
-
324
- # Lista de arquivos XML.gz do Carolina que tentaremos baixar (ordem: menores
325
- # taxonomias primeiro para minimizar banda e RAM). Selecionamos 2 arquivos
326
- # por taxonomia para garantir diversidade sem explodir a memória.
327
- CAROLINA_XML_FILES = [
328
- # taxonomia "datasets_and_other_corpora" (DAT = pt-BR notícias)
329
- "corpus/datasets_and_other_corpora/pt-BR/DATa.xml.gz",
330
- "corpus/datasets_and_other_corpora/pt-BR/DATb.xml.gz",
331
- # taxonomia "wik" (wikis)
332
- "corpus/wik/WIKa.xml.gz",
333
- "corpus/wik/WIKb.xml.gz",
334
- # taxonomia "uni" (university_domains)
335
- "corpus/uni/UNIa.xml.gz",
336
- "corpus/uni/UNIb.xml.gz",
337
- # taxonomia "pub" (public_domain_works)
338
- "corpus/pub/PUBa.xml.gz",
339
- "corpus/pub/PUBb.xml.gz",
340
- ]
341
-
342
-
343
- def _stream_carolina_direct(
344
- max_samples: int,
345
- hf_token: Optional[str] = None,
346
- timeout_per_file: int = 60,
347
- ) -> Iterator[Dict[str, Any]]:
348
- """Workaround V13.9.2-carolina: carrega Carolina sem usar o script Python.
349
-
350
- Baixa arquivos XML.gz diretamente do repo e faz parse streaming com
351
- lxml.etree.iterparse (compatível com datasets 5.0+). Cada <TEI> vira um
352
- documento de texto (concatenação dos <p> dentro de <body>).
353
-
354
- Args:
355
- max_samples: número máximo de amostras a retornar
356
- hf_token: token HF opcional (dataset é público, mas token evita rate limit)
357
- timeout_per_file: tempo máximo (segundos) por arquivo XML
358
-
359
- Yields:
360
- dict com chave "text" (compatível com _normalize_sample)
361
- """
362
- from huggingface_hub import hf_hub_download
363
- import gzip
364
- from lxml import etree
365
-
366
- TEI_NS = "{http://www.tei-c.org/ns/1.0}"
367
- BODY_P_TAG = f".//{TEI_NS}body/{TEI_NS}p"
368
-
369
- count = 0
370
- for xml_path in CAROLINA_XML_FILES:
371
- if count >= max_samples:
372
- return
373
- try:
374
- local_path = hf_hub_download(
375
- repo_id="carolina-c4ai/corpus-carolina",
376
- filename=xml_path,
377
- repo_type="dataset",
378
- token=hf_token,
379
- )
380
- except Exception as e:
381
- logger.warning(f"Carolina: não foi possível baixar {xml_path}: {e}")
382
- continue
383
-
384
- try:
385
- with gzip.open(local_path, "rb") as gz:
386
- # iterparse streaming: não carrega árvore inteira na memória
387
- for _, tei in etree.iterparse(
388
- gz, huge_tree=True, encoding="utf-8", tag=f"{TEI_NS}TEI"
389
- ):
390
- if count >= max_samples:
391
- tei.clear()
392
- return
393
- # Extrai texto dos <p> dentro de <body>
394
- parts = []
395
- for p in tei.findall(BODY_P_TAG):
396
- if p.text:
397
- parts.append(p.text)
398
- text = " ".join(parts).strip()
399
- if text and len(text) >= 10:
400
- yield {"text": text, "meta": ""}
401
- tei.clear() # libera memória da árvore TEI
402
- count += 1
403
- except Exception as e:
404
- logger.warning(f"Carolina: erro processando {xml_path}: {e}")
405
- continue
406
-
407
- logger.info(f"Carolina: streamou {count} amostras no total")
408
-
409
-
410
- # ═══════════════════════════════════════════════════════════════════════════
411
- # V13.9.2-finetune-v2: Loaders alternativos para datasets parquet grandes
412
- # onde datasets.load_dataset(streaming=True) é inviável (primeira amostra
413
- # demora minutos para materializar).
414
- # ═══════════════════════════════════════════════════════════════════════════
415
-
416
- def _stream_via_rows_api(
417
- dataset_name: str,
418
- max_samples: int,
419
- hf_token: Optional[str] = None,
420
- batch_size: int = 100,
421
- max_offset: int = 100_000,
422
- config: Optional[str] = None,
423
- split: str = "train",
424
- ) -> Iterator[Dict[str, Any]]:
425
- """Carrega amostras via HF datasets-server /rows API (HTTP).
426
-
427
- Usado para datasets cujo parquet é muito grande para streaming eficiente
428
- (ex: cnmoro/Instruct-PTBR-10M com 10 GB em arquivo único) OU datasets
429
- que usam script Python como loader (não suportado em datasets 5.0+,
430
- ex: adalbertojunior/punctuation-ptbr). A rows API retorna batches de
431
- até 100 rows via HTTP, sem precisar baixar o parquet.
432
-
433
- Args:
434
- dataset_name: repo_id do dataset (ex: "cnmoro/Instruct-PTBR-10M")
435
- max_samples: nº máximo de amostras a retornar
436
- hf_token: token HF (opcional — dataset público)
437
- batch_size: nº de rows por requisição (máx 100)
438
- max_offset: offset máximo a tentar (sai do loop se excedido)
439
- config: nome da config do dataset (default: "default"). NECESSÁRIO
440
- para datasets cuja config não é "default" (ex:
441
- adalbertojunior/punctuation-ptbr usa "punctuation-ptbr").
442
- split: nome do split (default: "train").
443
-
444
- Yields:
445
- dict com campos do dataset (compatível com _normalize_sample)
446
- """
447
- import json as _json
448
- import urllib.request
449
- import urllib.parse
450
-
451
- base_url = "https://datasets-server.huggingface.co/rows"
452
- config_name = config or "default"
453
- count = 0
454
- offset = 0
455
-
456
- while count < max_samples and offset < max_offset:
457
- params = urllib.parse.urlencode({
458
- "dataset": dataset_name,
459
- "config": config_name,
460
- "split": split,
461
- "offset": offset,
462
- "length": min(batch_size, max_samples - count),
463
- })
464
- url = f"{base_url}?{params}"
465
- try:
466
- req = urllib.request.Request(url)
467
- if hf_token:
468
- req.add_header("Authorization", f"Bearer {hf_token}")
469
- with urllib.request.urlopen(req, timeout=30) as r:
470
- data = _json.loads(r.read())
471
- except Exception as e:
472
- logger.warning(f"rows_api {dataset_name} config={config_name} offset={offset}: {e}")
473
- break
474
-
475
- rows = data.get("rows", [])
476
- if not rows:
477
- break
478
-
479
- for row in rows:
480
- if count >= max_samples:
481
- return
482
- row_data = row.get("row", {})
483
- # Remove campos internos como __index_level_0__
484
- clean = {k: v for k, v in row_data.items()
485
- if not k.startswith("__")}
486
- yield clean
487
- count += 1
488
-
489
- offset += len(rows)
490
- if len(rows) < batch_size:
491
- break # chegou ao fim do dataset
492
-
493
- logger.info(f"rows_api {dataset_name} config={config_name}: streamou {count} amostras")
494
-
495
-
496
- def _stream_via_parquet_first_shard(
497
- dataset_name: str,
498
- max_samples: int,
499
- hf_token: Optional[str] = None,
500
- ) -> Iterator[Dict[str, Any]]:
501
- """Baixa primeiro shard parquet do dataset e itera localmente com pyarrow.
502
-
503
- Usado para datasets com múltiplos shards parquet grandes (ex:
504
- strak2005/corpus-ptbr-v1 com 18 shards de ~1GB). Streaming via
505
- datasets.load_dataset() não materializa primeira amostra em tempo
506
- aceitável. Esta função baixa o primeiro shard (~26s para 1GB) e itera
507
- localmente — rápido após download.
508
-
509
- Args:
510
- dataset_name: repo_id do dataset
511
- max_samples: nº máximo de amostras
512
- hf_token: token HF opcional
513
-
514
- Yields:
515
- dict com campos do dataset
516
- """
517
- from huggingface_hub import HfApi, hf_hub_download
518
- import pyarrow.parquet as pq
519
-
520
- api = HfApi(token=hf_token)
521
-
522
- # Lista arquivos parquet no repo
523
- try:
524
- info = api.dataset_info(dataset_name)
525
- except Exception as e:
526
- logger.warning(f"parquet_shard {dataset_name}: dataset_info failed: {e}")
527
- return
528
-
529
- parquet_files = sorted([
530
- s.rfilename for s in info.siblings
531
- if s.rfilename.endswith(".parquet")
532
- ])
533
- if not parquet_files:
534
- logger.warning(f"parquet_shard {dataset_name}: nenhum .parquet encontrado")
535
- return
536
-
537
- # Baixa apenas o primeiro shard
538
- first_shard = parquet_files[0]
539
- logger.info(f"parquet_shard {dataset_name}: baixando {first_shard}...")
540
- try:
541
- local_path = hf_hub_download(
542
- repo_id=dataset_name,
543
- filename=first_shard,
544
- repo_type="dataset",
545
- token=hf_token,
546
- )
547
- except Exception as e:
548
- logger.warning(f"parquet_shard {dataset_name}: download failed: {e}")
549
- return
550
-
551
- # Itera com pyarrow.iter_batches — método eficiente que lê batches pequenos
552
- # do parquet sem materializar o row group inteiro na memória.
553
- # BUG FIX V13.9.2-finetune-v2: read_row_group() materializa TODAS as ~1M
554
- # rows de uma vez (lento + ~1GB RAM). iter_batches(batch_size=10) lê só
555
- # 10 rows por vez (rápido + ~10KB RAM).
556
- try:
557
- pf = pq.ParquetFile(local_path)
558
- count = 0
559
- # batch_read_size: nº de rows por batch (pequeno = menos RAM)
560
- for batch in pf.iter_batches(batch_size=100):
561
- if count >= max_samples:
562
- break
563
- cols = batch.schema.names
564
- # to_pylist() é eficiente para batches pequenos
565
- pydict = batch.to_pydict()
566
- n_rows = len(pydict[cols[0]]) if cols else 0
567
- for i in range(n_rows):
568
- if count >= max_samples:
569
- break
570
- row = {col: pydict[col][i] for col in cols}
571
- yield row
572
- count += 1
573
- except Exception as e:
574
- logger.warning(f"parquet_shard {dataset_name}: pyarrow iter failed: {e}")
575
- return
576
-
577
- logger.info(f"parquet_shard {dataset_name}: streamou {count} amostras do shard {first_shard}")
578
-
579
-
580
- @dataclass
581
- class ProcessedSample:
582
- """Uma amostra processada: texto bruto + metadados."""
583
- raw_text: str
584
- dataset_name: str
585
- sample_idx: int
586
- text_field: str = ""
587
- label_text: str = ""
588
-
589
-
590
- def _extract_field(sample: Dict[str, Any], candidate_fields: List[str]) -> Optional[str]:
591
- """Extrai texto da primeira field disponível no sample.
592
-
593
- Suporta:
594
- - strings diretas
595
- - listas de strings (join com espaço — útil para datasets tokenizados
596
- como adalbertojunior/punctuation-ptbr onde "tokens": ["hoje","a",...])
597
- - listas de dicts (chat messages — concatena role: content)
598
- - dicts aninhados (pega text/content/body)
599
- """
600
- for field_name in candidate_fields:
601
- if field_name in sample:
602
- val = sample[field_name]
603
- if val is None:
604
- continue
605
- if isinstance(val, str):
606
- if val.strip():
607
- return val
608
- elif isinstance(val, list):
609
- # V6.5-7ds: se for lista de strings, join com espaços
610
- # (ex: adalbertojunior/punctuation-ptbr tokens field)
611
- string_parts = []
612
- chat_parts = []
613
- all_strings = True
614
- for item in val:
615
- if isinstance(item, str):
616
- if item.strip():
617
- string_parts.append(item)
618
- elif isinstance(item, (int, float)):
619
- # tokens podem vir como ints (token IDs) — skip
620
- all_strings = False
621
- break
622
- elif isinstance(item, dict):
623
- all_strings = False
624
- role = item.get("role", "")
625
- content = item.get("content", "")
626
- if isinstance(content, str) and content.strip():
627
- chat_parts.append(f"{role}: {content}")
628
- else:
629
- all_strings = False
630
- if all_strings and string_parts:
631
- joined = " ".join(string_parts).strip()
632
- if joined:
633
- return joined
634
- if chat_parts:
635
- return "\n".join(chat_parts)
636
- elif isinstance(val, dict):
637
- # Pode ser nested
638
- text = val.get("text") or val.get("content") or val.get("body")
639
- if isinstance(text, str) and text.strip():
640
- return text
641
- return None
642
-
643
-
644
- def _normalize_sample(sample: Dict[str, Any], dataset_name: str, idx: int) -> Optional[ProcessedSample]:
645
- """Normaliza uma amostra bruta em ProcessedSample."""
646
- fmt = DATASET_FORMATS.get(dataset_name, {})
647
- text_fields = fmt.get("text_fields", ["text"])
648
- label_fields = fmt.get("label_fields", [])
649
-
650
- text = _extract_field(sample, text_fields)
651
- if not text or len(text.strip()) < 10: # skip very short
652
- return None
653
-
654
- label = ""
655
- if label_fields:
656
- label = _extract_field(sample, label_fields) or ""
657
-
658
- # Se tem label, aplica template apropriado
659
- template = fmt.get("format_template")
660
- full_text = text
661
-
662
- # V13.9.2-finetune-v3: para o template instruction_response, exige ambos
663
- # os lados (instruction + response). Samples sem response são descartados
664
- # para evitar treinar em texto parcial.
665
- if template == "instruction_response" and not label:
666
- return None
667
-
668
- if label:
669
- # V13.9.2-finetune-v3: format_template unificado "### Instruction:/### Response:"
670
- # quando o dataset declarar explicitamente. Caso contrário, mantém o
671
- # comportamento legado (concatenação simples text\nlabel) para os 9
672
- # datasets base — retrocompatibilidade total.
673
- if template == "instruction_response":
674
- instr_prefix = fmt.get("instruction_prefix", "")
675
- if instr_prefix:
676
- full_text = (
677
- f"### Instruction:\n{instr_prefix}\n{text}\n\n"
678
- f"### Response:\n{label}"
679
- )
680
- else:
681
- full_text = (
682
- f"### Instruction:\n{text}\n\n"
683
- f"### Response:\n{label}"
684
- )
685
- elif template == "title_text_concat":
686
- # V6.5-7ds: para datasets de notícias (iara-project, manoela),
687
- # o campo "text" (corpo da notícia) é o conteúdo principal e
688
- # "category" (categoria) é o contexto temático. Formatamos como
689
- # "TEXTO: <corpo>\nCATEGORIA: <categoria>".
690
- full_text = f"TEXTO: {text}\nCATEGORIA: {label}"
691
- else:
692
- # Comportamento legado (9 datasets base): concatenação simples
693
- full_text = f"{text}\n{label}"
694
-
695
- return ProcessedSample(
696
- raw_text=full_text,
697
- dataset_name=dataset_name,
698
- sample_idx=idx,
699
- text_field=text_fields[0] if text_fields else "",
700
- label_text=label,
701
- )
702
-
703
-
704
- def _load_dataset_streaming(
705
- dataset_name: str,
706
- split: str = "train",
707
- config: Optional[str] = None,
708
- hf_token: Optional[str] = None,
709
- ):
710
- """Carrega dataset em modo streaming.
711
-
712
- BUG FIX V13.9.1: Removido trust_remote_code (deprecated).
713
- Se o dataset não carregar com split especificado, tenta 'train' como fallback.
714
- BUG FIX V13.9.2: Adicionado fallback para datasets com script (carolina-c4ai).
715
- """
716
- from datasets import load_dataset
717
-
718
- # Lista de splits para tentar, em ordem
719
- splits_to_try = [split]
720
- if split != "train":
721
- splits_to_try.append("train")
722
- # Adiciona outros splits comuns
723
- for s in ["test", "validation", "cot", "tir"]:
724
- if s not in splits_to_try:
725
- splits_to_try.append(s)
726
-
727
- fmt = DATASET_FORMATS.get(dataset_name, {})
728
- fallback_name = fmt.get("fallback")
729
- datasets_to_try = [dataset_name]
730
- if fallback_name:
731
- datasets_to_try.append(fallback_name)
732
-
733
- for try_ds_name in datasets_to_try:
734
- for try_split in splits_to_try:
735
- try:
736
- if config:
737
- ds = load_dataset(
738
- try_ds_name, config, split=try_split, streaming=True,
739
- token=hf_token,
740
- )
741
- else:
742
- ds = load_dataset(
743
- try_ds_name, split=try_split, streaming=True,
744
- token=hf_token,
745
- )
746
- logger.info(f"Loaded {try_ds_name} split={try_split}")
747
- return ds
748
- except Exception as e:
749
- err_str = str(e).lower()
750
- # If "Bad split" error, try next split
751
- if "bad split" in err_str or "available splits" in err_str:
752
- logger.info(f" Split {try_split} not available for {try_ds_name}, trying next")
753
- continue
754
- # If "scripts no longer supported", try next dataset (fallback)
755
- if "scripts are no longer supported" in err_str and fallback_name:
756
- logger.info(f" {try_ds_name} uses script — trying fallback {fallback_name}")
757
- break
758
- # For other errors, log and try next split
759
- logger.warning(f"Failed to load {try_ds_name} split={try_split}: {str(e)[:120]}")
760
- continue
761
-
762
- logger.warning(f"All split attempts failed for {dataset_name} (will be skipped)")
763
- return None
764
-
765
-
766
- def stream_dataset(
767
- dataset_name: str,
768
- max_samples: int = 500,
769
- hf_token: Optional[str] = None,
770
- ) -> Iterator[ProcessedSample]:
771
- """Faz streaming de um dataset, retornando até max_samples amostras.
772
-
773
- Args:
774
- dataset_name: nome do dataset no HuggingFace
775
- max_samples: número máximo de amostras a retornar
776
- hf_token: token HF opcional
777
-
778
- Yields:
779
- ProcessedSample
780
- """
781
- fmt = DATASET_FORMATS.get(dataset_name)
782
- if fmt is None:
783
- logger.error(f"Unknown dataset: {dataset_name}")
784
- return
785
-
786
- # ── V13.9.2-carolina: bypass do script Python ─────────────────────────
787
- # O dataset carolina-c4ai/corpus-carolina usa um script Python como loader,
788
- # que não é suportado por datasets 5.0+. Streamamos os XML.gz diretamente.
789
- if dataset_name == "carolina-c4ai/corpus-carolina":
790
- logger.info(f"Carolina: usando carregador direto (bypass do script Python)")
791
- count = 0
792
- try:
793
- for raw_sample in _stream_carolina_direct(
794
- max_samples=max_samples, hf_token=hf_token
795
- ):
796
- processed = _normalize_sample(raw_sample, dataset_name, count)
797
- if processed is not None:
798
- yield processed
799
- count += 1
800
- except Exception as e:
801
- logger.warning(f"Carolina direct stream error at sample {count}: {e}")
802
- return
803
- logger.info(f"Streamed {count} samples from {dataset_name} (direct XML)")
804
- return
805
-
806
- # ── V13.9.2-finetune-v2: loaders alternativos para parquets grandes ───
807
- # Alguns datasets (cnmoro, strak2005/bratao) têm parquets tão grandes que
808
- # datasets.load_dataset(streaming=True) demora minutos para materializar
809
- # a primeira amostra. Usamos loaders alternativos especificados no campo
810
- # "loader" do formato.
811
- loader = fmt.get("loader")
812
- if loader == "rows_api":
813
- logger.info(f"{dataset_name}: usando rows_api loader (datasets-server HTTP)")
814
- count = 0
815
- try:
816
- for raw_sample in _stream_via_rows_api(
817
- dataset_name, max_samples=max_samples, hf_token=hf_token,
818
- config=fmt.get("config"),
819
- split=fmt.get("split", "train"),
820
- ):
821
- processed = _normalize_sample(raw_sample, dataset_name, count)
822
- if processed is not None:
823
- yield processed
824
- count += 1
825
- except Exception as e:
826
- logger.warning(f"rows_api stream error at sample {count}: {e}")
827
- return
828
- logger.info(f"Streamed {count} samples from {dataset_name} (rows_api)")
829
- return
830
-
831
- if loader == "parquet_first_shard":
832
- logger.info(f"{dataset_name}: usando parquet_first_shard loader")
833
- count = 0
834
- try:
835
- for raw_sample in _stream_via_parquet_first_shard(
836
- dataset_name, max_samples=max_samples, hf_token=hf_token
837
- ):
838
- processed = _normalize_sample(raw_sample, dataset_name, count)
839
- if processed is not None:
840
- yield processed
841
- count += 1
842
- except Exception as e:
843
- logger.warning(f"parquet_shard stream error at sample {count}: {e}")
844
- # Tenta fallback (ex: strak2005 -> bratao)
845
- fallback_name = fmt.get("fallback")
846
- if fallback_name and fallback_name != dataset_name:
847
- logger.info(f"Tentando fallback: {fallback_name}")
848
- fallback_fmt = DATASET_FORMATS.get(fallback_name, {})
849
- # Recursão respeitando o loader do fallback
850
- yield from stream_dataset(
851
- fallback_name, max_samples=max_samples, hf_token=hf_token
852
- )
853
- return
854
- logger.info(f"Streamed {count} samples from {dataset_name} (parquet_first_shard)")
855
- return
856
-
857
- ds = _load_dataset_streaming(
858
- dataset_name,
859
- split=fmt.get("split", "train"),
860
- config=fmt.get("config"),
861
- hf_token=hf_token,
862
- )
863
- if ds is None:
864
- return
865
-
866
- count = 0
867
- try:
868
- for idx, sample in enumerate(ds):
869
- if count >= max_samples:
870
- break
871
- processed = _normalize_sample(sample, dataset_name, idx)
872
- if processed is not None:
873
- yield processed
874
- count += 1
875
- except Exception as e:
876
- logger.warning(f"Error streaming {dataset_name} at sample {idx}: {e}")
877
- return
878
-
879
- logger.info(f"Streamed {count} samples from {dataset_name}")
880
-
881
-
882
- def stream_all_datasets(
883
- datasets: Optional[List[str]] = None,
884
- max_samples_per_dataset: int = 500,
885
- hf_token: Optional[str] = None,
886
- ) -> Iterator[ProcessedSample]:
887
- """Faz streaming sequencial de múltiplos datasets.
888
-
889
- Args:
890
- datasets: lista de nomes (default: DEFAULT_DATASETS)
891
- max_samples_per_dataset: limite por dataset
892
- hf_token: token HF opcional
893
-
894
- Yields:
895
- ProcessedSample
896
- """
897
- if datasets is None:
898
- datasets = DEFAULT_DATASETS
899
-
900
- for ds_name in datasets:
901
- logger.info(f"Starting dataset: {ds_name}")
902
- yield from stream_dataset(
903
- ds_name,
904
- max_samples=max_samples_per_dataset,
905
- hf_token=hf_token,
906
- )
907
-
908
-
909
- def collate_samples_to_tensors(
910
- samples: List[ProcessedSample],
911
- tokenizer,
912
- max_seq_len: int = 64,
913
- pad_token_id: int = 0,
914
- ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
915
- """Converte lista de ProcessedSample em tensors para treino.
916
-
917
- BUG FIX V13.9.1: Tokenizer.encode() retorna 'Encoding' object, não list.
918
- Use .ids attribute to get token IDs.
919
-
920
- Returns:
921
- input_ids: (B, T)
922
- attention_mask: (B, T)
923
- labels: (B, T) — same as input_ids (LM training)
924
- """
925
- batch_input_ids = []
926
- batch_attn_mask = []
927
-
928
- for sample in samples:
929
- # Tokenize
930
- encoding = tokenizer.encode(sample.raw_text, add_special_tokens=True)
931
-
932
- # BUG FIX: Handle both `tokenizers.Encoding` and `transformers` tokenizer outputs
933
- if hasattr(encoding, 'ids'):
934
- tokens = encoding.ids # tokenizers library
935
- elif isinstance(encoding, list):
936
- tokens = encoding # already a list of ints
937
- elif hasattr(encoding, 'input_ids'):
938
- tokens = encoding.input_ids # transformers BatchEncoding
939
- else:
940
- tokens = list(encoding) # fallback
941
-
942
- # Truncate to max_seq_len
943
- if len(tokens) > max_seq_len:
944
- tokens = tokens[:max_seq_len]
945
- # Pad
946
- attn_mask = [1] * len(tokens) + [0] * (max_seq_len - len(tokens))
947
- tokens = list(tokens) + [pad_token_id] * (max_seq_len - len(tokens))
948
- batch_input_ids.append(tokens)
949
- batch_attn_mask.append(attn_mask)
950
-
951
- input_ids = torch.tensor(batch_input_ids, dtype=torch.long)
952
- attention_mask = torch.tensor(batch_attn_mask, dtype=torch.long)
953
- labels = input_ids.clone()
954
-
955
- return input_ids, attention_mask, labels
956
-
957
-
958
- # ═══════════════════════════════════════════════════════════════════════════
959
- # Self-test (NÃO enviar para HuggingFace)
960
- # ═══════════════════════════════════════════════════════════════════════════
961
- if __name__ == "__main__":
962
- print("=== Streaming Datasets V13.9.1 Self-Test ===\n")
963
-
964
- # Test 1: Test field extraction
965
- print("Test 1: Field extraction")
966
- sample_chat = {
967
- "messages": [
968
- {"role": "user", "content": "Olá"},
969
- {"role": "assistant", "content": "Como posso ajudar?"},
970
- ]
971
- }
972
- text = _extract_field(sample_chat, ["messages", "text"])
973
- print(f" Chat text: {text!r}")
974
- assert text and "Olá" in text, "Field extraction failed for chat"
975
-
976
- sample_text = {"text": "Hello world"}
977
- text = _extract_field(sample_text, ["text", "content"])
978
- assert text == "Hello world"
979
- print(f" Text field: {text!r}")
980
- print(f" OK\n")
981
-
982
- # Test 2: Test list of datasets
983
- print("Test 2: Dataset list")
984
- print(f" Configured datasets ({len(DEFAULT_DATASETS)}):")
985
- for i, ds in enumerate(DEFAULT_DATASETS, 1):
986
- print(f" {i}. {ds}")
987
- assert len(DEFAULT_DATASETS) == 14
988
- # V6.5-V2: verifica sequência CONHECIMENTO (8 datasets) + PUNICAO (1)
989
- assert len(CONHECIMENTO_DATASETS_V2) == 8
990
- assert PUNICAO_DATASET_V2 == "BrunoN-Dev/corpus-ptbr-v1"
991
- print(f" V2 CONHECIMENTO datasets: {len(CONHECIMENTO_DATASETS_V2)}")
992
- print(f" V2 PUNICAO dataset: {PUNICAO_DATASET_V2}")
993
- print(f" OK\n")
994
-
995
- print("=== ALL STREAMING TESTS PASSED ===")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
train_v6_5_v2.py DELETED
The diff for this file is too large to render. See raw diff
 
v6_5_v2_attention_eval.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "evaluation": "attention_v65_v2",
3
- "user_requirement": "verificar se o mecanismo de atenção está ativo e acessado logicamente funcional",
4
- "metrics": {
5
- "active": true,
6
- "n_calls": 500,
7
- "n_errors": 0,
8
- "last_norm_in": 108.67192077636719,
9
- "last_norm_out": 112.93913269042969,
10
- "last_attn_activated": true,
11
- "last_attn_diff_norm": 114.95559692382812,
12
- "n_heads": 8,
13
- "logic_functional": true
14
- },
15
- "active": true,
16
- "logic_functional": true,
17
- "n_calls": 500,
18
- "n_errors": 0,
19
- "n_heads": 8,
20
- "assessment": "PASS"
21
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v6_5_v2_phases_eval.json DELETED
@@ -1,1414 +0,0 @@
1
- {
2
- "fase_1_conhecimento": {
3
- "phase": "CONHECIMENTO",
4
- "total_samples": 500,
5
- "meta_minima": 8000,
6
- "meta_atingida": false,
7
- "samples_per_dataset": {
8
- "dominguesm/restore-punctuation-ptbr-dataset": 500,
9
- "carolina-c4ai/corpus-carolina": 0,
10
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": 0,
11
- "dominguesm/Canarim-Instruct-PTBR-Dataset": 0,
12
- "adalbertojunior/punctuation-ptbr": 0,
13
- "iara-project/news-articles-ptbr-dataset": 0,
14
- "manoela/noticias_ptbr": 0,
15
- "BrunoN-Dev/corpus-ptbr-v1": 0
16
- },
17
- "streaming_failures": {
18
- "dominguesm/restore-punctuation-ptbr-dataset": 0,
19
- "carolina-c4ai/corpus-carolina": 0,
20
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": 0,
21
- "dominguesm/Canarim-Instruct-PTBR-Dataset": 0,
22
- "adalbertojunior/punctuation-ptbr": 0,
23
- "iara-project/news-articles-ptbr-dataset": 0,
24
- "manoela/noticias_ptbr": 0,
25
- "BrunoN-Dev/corpus-ptbr-v1": 0
26
- },
27
- "storage_critical_stopped": true,
28
- "elapsed_s": 37.09058332443237,
29
- "n_steps": 35,
30
- "n_chunks": 5,
31
- "accuracies_log": [
32
- {
33
- "step": 0,
34
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
35
- "chunk_idx": 1,
36
- "batch_size": 16,
37
- "accuracy": 0.9375,
38
- "phase": "CONHECIMENTO",
39
- "buffer_size": 16,
40
- "training_ready": true,
41
- "elapsed_ms": 383.3961486816406
42
- },
43
- {
44
- "step": 1,
45
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
46
- "chunk_idx": 1,
47
- "batch_size": 16,
48
- "accuracy": 0.9375,
49
- "phase": "CONHECIMENTO",
50
- "buffer_size": 32,
51
- "training_ready": true,
52
- "elapsed_ms": 105.80253601074219
53
- },
54
- {
55
- "step": 2,
56
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
57
- "chunk_idx": 1,
58
- "batch_size": 16,
59
- "accuracy": 0.9791666666666666,
60
- "phase": "CONHECIMENTO",
61
- "buffer_size": 48,
62
- "training_ready": true,
63
- "elapsed_ms": 146.81077003479004
64
- },
65
- {
66
- "step": 3,
67
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
68
- "chunk_idx": 1,
69
- "batch_size": 16,
70
- "accuracy": 0.984375,
71
- "phase": "CONHECIMENTO",
72
- "buffer_size": 64,
73
- "training_ready": true,
74
- "elapsed_ms": 166.37229919433594
75
- },
76
- {
77
- "step": 4,
78
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
79
- "chunk_idx": 1,
80
- "batch_size": 16,
81
- "accuracy": 1.0,
82
- "phase": "CONHECIMENTO",
83
- "buffer_size": 80,
84
- "training_ready": true,
85
- "elapsed_ms": 226.5923023223877
86
- },
87
- {
88
- "step": 5,
89
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
90
- "chunk_idx": 1,
91
- "batch_size": 16,
92
- "accuracy": 0.9895833333333334,
93
- "phase": "CONHECIMENTO",
94
- "buffer_size": 96,
95
- "training_ready": true,
96
- "elapsed_ms": 256.2379837036133
97
- },
98
- {
99
- "step": 6,
100
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
101
- "chunk_idx": 1,
102
- "batch_size": 4,
103
- "accuracy": 0.98,
104
- "phase": "CONHECIMENTO",
105
- "buffer_size": 100,
106
- "training_ready": true,
107
- "elapsed_ms": 236.21749877929688
108
- },
109
- {
110
- "step": 7,
111
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
112
- "chunk_idx": 2,
113
- "batch_size": 16,
114
- "accuracy": 0.9482758620689655,
115
- "phase": "CONHECIMENTO",
116
- "buffer_size": 116,
117
- "training_ready": true,
118
- "elapsed_ms": 329.33592796325684
119
- },
120
- {
121
- "step": 8,
122
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
123
- "chunk_idx": 2,
124
- "batch_size": 16,
125
- "accuracy": 0.9393939393939394,
126
- "phase": "CONHECIMENTO",
127
- "buffer_size": 132,
128
- "training_ready": true,
129
- "elapsed_ms": 356.5490245819092
130
- },
131
- {
132
- "step": 9,
133
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
134
- "chunk_idx": 2,
135
- "batch_size": 16,
136
- "accuracy": 0.9324324324324325,
137
- "phase": "CONHECIMENTO",
138
- "buffer_size": 148,
139
- "training_ready": true,
140
- "elapsed_ms": 368.1018352508545
141
- },
142
- {
143
- "step": 10,
144
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
145
- "chunk_idx": 2,
146
- "batch_size": 16,
147
- "accuracy": 0.9390243902439024,
148
- "phase": "CONHECIMENTO",
149
- "buffer_size": 164,
150
- "training_ready": true,
151
- "elapsed_ms": 498.46649169921875
152
- },
153
- {
154
- "step": 11,
155
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
156
- "chunk_idx": 2,
157
- "batch_size": 16,
158
- "accuracy": 0.9388888888888889,
159
- "phase": "CONHECIMENTO",
160
- "buffer_size": 180,
161
- "training_ready": true,
162
- "elapsed_ms": 428.97915840148926
163
- },
164
- {
165
- "step": 12,
166
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
167
- "chunk_idx": 2,
168
- "batch_size": 16,
169
- "accuracy": 0.9336734693877551,
170
- "phase": "CONHECIMENTO",
171
- "buffer_size": 196,
172
- "training_ready": true,
173
- "elapsed_ms": 450.5326747894287
174
- },
175
- {
176
- "step": 13,
177
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
178
- "chunk_idx": 2,
179
- "batch_size": 4,
180
- "accuracy": 0.935,
181
- "phase": "CONHECIMENTO",
182
- "buffer_size": 200,
183
- "training_ready": true,
184
- "elapsed_ms": 688.495397567749
185
- },
186
- {
187
- "step": 14,
188
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
189
- "chunk_idx": 3,
190
- "batch_size": 16,
191
- "accuracy": 0.8958333333333334,
192
- "phase": "CONHECIMENTO",
193
- "buffer_size": 144,
194
- "training_ready": true,
195
- "elapsed_ms": 360.4564666748047
196
- },
197
- {
198
- "step": 15,
199
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
200
- "chunk_idx": 3,
201
- "batch_size": 16,
202
- "accuracy": 0.9,
203
- "phase": "CONHECIMENTO",
204
- "buffer_size": 160,
205
- "training_ready": true,
206
- "elapsed_ms": 377.14409828186035
207
- },
208
- {
209
- "step": 16,
210
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
211
- "chunk_idx": 3,
212
- "batch_size": 16,
213
- "accuracy": 0.8977272727272727,
214
- "phase": "CONHECIMENTO",
215
- "buffer_size": 176,
216
- "training_ready": true,
217
- "elapsed_ms": 533.5609912872314
218
- },
219
- {
220
- "step": 17,
221
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
222
- "chunk_idx": 3,
223
- "batch_size": 16,
224
- "accuracy": 0.8958333333333334,
225
- "phase": "CONHECIMENTO",
226
- "buffer_size": 192,
227
- "training_ready": true,
228
- "elapsed_ms": 428.7114143371582
229
- },
230
- {
231
- "step": 18,
232
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
233
- "chunk_idx": 3,
234
- "batch_size": 16,
235
- "accuracy": 0.8990384615384616,
236
- "phase": "CONHECIMENTO",
237
- "buffer_size": 208,
238
- "training_ready": true,
239
- "elapsed_ms": 477.15067863464355
240
- },
241
- {
242
- "step": 19,
243
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
244
- "chunk_idx": 3,
245
- "batch_size": 16,
246
- "accuracy": 0.8928571428571429,
247
- "phase": "CONHECIMENTO",
248
- "buffer_size": 224,
249
- "training_ready": true,
250
- "elapsed_ms": 530.5352210998535
251
- },
252
- {
253
- "step": 20,
254
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
255
- "chunk_idx": 3,
256
- "batch_size": 4,
257
- "accuracy": 0.8903508771929824,
258
- "phase": "CONHECIMENTO",
259
- "buffer_size": 228,
260
- "training_ready": true,
261
- "elapsed_ms": 529.3123722076416
262
- },
263
- {
264
- "step": 21,
265
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
266
- "chunk_idx": 4,
267
- "batch_size": 16,
268
- "accuracy": 0.8958333333333334,
269
- "phase": "CONHECIMENTO",
270
- "buffer_size": 144,
271
- "training_ready": true,
272
- "elapsed_ms": 378.77631187438965
273
- },
274
- {
275
- "step": 22,
276
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
277
- "chunk_idx": 4,
278
- "batch_size": 16,
279
- "accuracy": 0.9,
280
- "phase": "CONHECIMENTO",
281
- "buffer_size": 160,
282
- "training_ready": true,
283
- "elapsed_ms": 772.2029685974121
284
- },
285
- {
286
- "step": 23,
287
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
288
- "chunk_idx": 4,
289
- "batch_size": 16,
290
- "accuracy": 0.9034090909090909,
291
- "phase": "CONHECIMENTO",
292
- "buffer_size": 176,
293
- "training_ready": true,
294
- "elapsed_ms": 374.96161460876465
295
- },
296
- {
297
- "step": 24,
298
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
299
- "chunk_idx": 4,
300
- "batch_size": 16,
301
- "accuracy": 0.9114583333333334,
302
- "phase": "CONHECIMENTO",
303
- "buffer_size": 192,
304
- "training_ready": true,
305
- "elapsed_ms": 416.3072109222412
306
- },
307
- {
308
- "step": 25,
309
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
310
- "chunk_idx": 4,
311
- "batch_size": 16,
312
- "accuracy": 0.9086538461538461,
313
- "phase": "CONHECIMENTO",
314
- "buffer_size": 208,
315
- "training_ready": true,
316
- "elapsed_ms": 850.2218723297119
317
- },
318
- {
319
- "step": 26,
320
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
321
- "chunk_idx": 4,
322
- "batch_size": 16,
323
- "accuracy": 0.9151785714285714,
324
- "phase": "CONHECIMENTO",
325
- "buffer_size": 224,
326
- "training_ready": true,
327
- "elapsed_ms": 491.5575981140137
328
- },
329
- {
330
- "step": 27,
331
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
332
- "chunk_idx": 4,
333
- "batch_size": 4,
334
- "accuracy": 0.9122807017543859,
335
- "phase": "CONHECIMENTO",
336
- "buffer_size": 228,
337
- "training_ready": true,
338
- "elapsed_ms": 455.5957317352295
339
- },
340
- {
341
- "step": 28,
342
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
343
- "chunk_idx": 5,
344
- "batch_size": 16,
345
- "accuracy": 0.9097222222222222,
346
- "phase": "CONHECIMENTO",
347
- "buffer_size": 144,
348
- "training_ready": true,
349
- "elapsed_ms": 335.35003662109375
350
- },
351
- {
352
- "step": 29,
353
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
354
- "chunk_idx": 5,
355
- "batch_size": 16,
356
- "accuracy": 0.9125,
357
- "phase": "CONHECIMENTO",
358
- "buffer_size": 160,
359
- "training_ready": true,
360
- "elapsed_ms": 337.5859260559082
361
- },
362
- {
363
- "step": 30,
364
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
365
- "chunk_idx": 5,
366
- "batch_size": 16,
367
- "accuracy": 0.8977272727272727,
368
- "phase": "CONHECIMENTO",
369
- "buffer_size": 176,
370
- "training_ready": true,
371
- "elapsed_ms": 411.2229347229004
372
- },
373
- {
374
- "step": 31,
375
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
376
- "chunk_idx": 5,
377
- "batch_size": 16,
378
- "accuracy": 0.90625,
379
- "phase": "CONHECIMENTO",
380
- "buffer_size": 192,
381
- "training_ready": true,
382
- "elapsed_ms": 742.3462867736816
383
- },
384
- {
385
- "step": 32,
386
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
387
- "chunk_idx": 5,
388
- "batch_size": 16,
389
- "accuracy": 0.9086538461538461,
390
- "phase": "CONHECIMENTO",
391
- "buffer_size": 208,
392
- "training_ready": true,
393
- "elapsed_ms": 1044.4471836090088
394
- },
395
- {
396
- "step": 33,
397
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
398
- "chunk_idx": 5,
399
- "batch_size": 16,
400
- "accuracy": 0.90625,
401
- "phase": "CONHECIMENTO",
402
- "buffer_size": 224,
403
- "training_ready": true,
404
- "elapsed_ms": 510.6990337371826
405
- },
406
- {
407
- "step": 34,
408
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
409
- "chunk_idx": 5,
410
- "batch_size": 4,
411
- "accuracy": 0.8991228070175439,
412
- "phase": "CONHECIMENTO",
413
- "buffer_size": 228,
414
- "training_ready": true,
415
- "elapsed_ms": 536.2398624420166
416
- }
417
- ],
418
- "attention_log": [
419
- {
420
- "step": 12,
421
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
422
- "n_calls": 196,
423
- "n_errors": 0,
424
- "last_attn_activated": true,
425
- "logic_functional": true
426
- },
427
- {
428
- "step": 14,
429
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
430
- "n_calls": 216,
431
- "n_errors": 0,
432
- "last_attn_activated": true,
433
- "logic_functional": true
434
- },
435
- {
436
- "step": 15,
437
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
438
- "n_calls": 232,
439
- "n_errors": 0,
440
- "last_attn_activated": true,
441
- "logic_functional": true
442
- },
443
- {
444
- "step": 16,
445
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
446
- "n_calls": 248,
447
- "n_errors": 0,
448
- "last_attn_activated": true,
449
- "logic_functional": true
450
- },
451
- {
452
- "step": 17,
453
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
454
- "n_calls": 264,
455
- "n_errors": 0,
456
- "last_attn_activated": true,
457
- "logic_functional": true
458
- },
459
- {
460
- "step": 18,
461
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
462
- "n_calls": 280,
463
- "n_errors": 0,
464
- "last_attn_activated": true,
465
- "logic_functional": true
466
- },
467
- {
468
- "step": 19,
469
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
470
- "n_calls": 296,
471
- "n_errors": 0,
472
- "last_attn_activated": true,
473
- "logic_functional": true
474
- },
475
- {
476
- "step": 21,
477
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
478
- "n_calls": 316,
479
- "n_errors": 0,
480
- "last_attn_activated": true,
481
- "logic_functional": true
482
- },
483
- {
484
- "step": 22,
485
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
486
- "n_calls": 332,
487
- "n_errors": 0,
488
- "last_attn_activated": true,
489
- "logic_functional": true
490
- },
491
- {
492
- "step": 23,
493
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
494
- "n_calls": 348,
495
- "n_errors": 0,
496
- "last_attn_activated": true,
497
- "logic_functional": true
498
- },
499
- {
500
- "step": 24,
501
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
502
- "n_calls": 364,
503
- "n_errors": 0,
504
- "last_attn_activated": true,
505
- "logic_functional": true
506
- },
507
- {
508
- "step": 25,
509
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
510
- "n_calls": 380,
511
- "n_errors": 0,
512
- "last_attn_activated": true,
513
- "logic_functional": true
514
- },
515
- {
516
- "step": 26,
517
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
518
- "n_calls": 396,
519
- "n_errors": 0,
520
- "last_attn_activated": true,
521
- "logic_functional": true
522
- },
523
- {
524
- "step": 28,
525
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
526
- "n_calls": 416,
527
- "n_errors": 0,
528
- "last_attn_activated": true,
529
- "logic_functional": true
530
- },
531
- {
532
- "step": 29,
533
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
534
- "n_calls": 432,
535
- "n_errors": 0,
536
- "last_attn_activated": true,
537
- "logic_functional": true
538
- },
539
- {
540
- "step": 30,
541
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
542
- "n_calls": 448,
543
- "n_errors": 0,
544
- "last_attn_activated": true,
545
- "logic_functional": true
546
- },
547
- {
548
- "step": 31,
549
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
550
- "n_calls": 464,
551
- "n_errors": 0,
552
- "last_attn_activated": true,
553
- "logic_functional": true
554
- },
555
- {
556
- "step": 32,
557
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
558
- "n_calls": 480,
559
- "n_errors": 0,
560
- "last_attn_activated": true,
561
- "logic_functional": true
562
- },
563
- {
564
- "step": 33,
565
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
566
- "n_calls": 496,
567
- "n_errors": 0,
568
- "last_attn_activated": true,
569
- "logic_functional": true
570
- },
571
- {
572
- "step": 34,
573
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
574
- "n_calls": 500,
575
- "n_errors": 0,
576
- "last_attn_activated": true,
577
- "logic_functional": true
578
- }
579
- ],
580
- "som_metrics_log": [
581
- {
582
- "step": 7,
583
- "chunk_idx": 1,
584
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
585
- "quantization_error": 2.26032170758117e-05,
586
- "topological_error": 0.880000002682209,
587
- "kaski_lagus_error": 0.4445206419101888,
588
- "explained_variance_share": 0.999451068570896,
589
- "overall_health": "critical",
590
- "n_failure_indicators": 3,
591
- "failure_indicators": [
592
- "topological_collapse_line",
593
- "dead_neuron_rate_high_0.89",
594
- "high_topological_error_0.88"
595
- ],
596
- "collapse_severity": "line",
597
- "dead_neuron_rate": 0.8900462962962963,
598
- "nan_detected": false,
599
- "nan_reason": null,
600
- "qe_was_nan": false,
601
- "kl_was_nan": false,
602
- "n_hypotheses_active": 0,
603
- "n_hypotheses_total": 16,
604
- "hypothesis_activation_rate": 0.0,
605
- "mean_delta_norm": 1.891924029278399e-12,
606
- "max_delta_norm": 2.1833108238000776e-12,
607
- "n_active_neurons_bmu": 95,
608
- "n_dead_neurons_bmu": 769,
609
- "neuron_activation_rate": 0.1099537037037037,
610
- "current_hyp_train_steps": 30,
611
- "total_hyp_steps_executed": 0,
612
- "n_train_hyp_calls": 0
613
- },
614
- {
615
- "step": 14,
616
- "chunk_idx": 2,
617
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
618
- "quantization_error": 0.000569911440834403,
619
- "topological_error": 0.9140625,
620
- "kaski_lagus_error": 0.5460798889633685,
621
- "explained_variance_share": 0.928539884025705,
622
- "overall_health": "critical",
623
- "n_failure_indicators": 3,
624
- "failure_indicators": [
625
- "topological_collapse_line",
626
- "dead_neuron_rate_high_0.95",
627
- "high_topological_error_0.91"
628
- ],
629
- "collapse_severity": "line",
630
- "dead_neuron_rate": 0.9456018518518519,
631
- "nan_detected": false,
632
- "nan_reason": null,
633
- "qe_was_nan": false,
634
- "kl_was_nan": false,
635
- "n_hypotheses_active": 0,
636
- "n_hypotheses_total": 16,
637
- "hypothesis_activation_rate": 0.0,
638
- "mean_delta_norm": 1.570570957358866e-11,
639
- "max_delta_norm": 1.831555566933485e-11,
640
- "n_active_neurons_bmu": 47,
641
- "n_dead_neurons_bmu": 817,
642
- "neuron_activation_rate": 0.05439814814814815,
643
- "current_hyp_train_steps": 30,
644
- "total_hyp_steps_executed": 0,
645
- "n_train_hyp_calls": 0
646
- },
647
- {
648
- "step": 21,
649
- "chunk_idx": 3,
650
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
651
- "quantization_error": 0.005070194136351347,
652
- "topological_error": 0.984375,
653
- "kaski_lagus_error": 1.2844052385351477,
654
- "explained_variance_share": 0.05886936612972116,
655
- "overall_health": "critical",
656
- "n_failure_indicators": 4,
657
- "failure_indicators": [
658
- "topological_collapse_line",
659
- "dead_neuron_rate_high_0.99",
660
- "low_explained_variance_0.06",
661
- "high_topological_error_0.98"
662
- ],
663
- "collapse_severity": "line",
664
- "dead_neuron_rate": 0.9884259259259259,
665
- "nan_detected": false,
666
- "nan_reason": null,
667
- "qe_was_nan": false,
668
- "kl_was_nan": false,
669
- "n_hypotheses_active": 0,
670
- "n_hypotheses_total": 16,
671
- "hypothesis_activation_rate": 0.0,
672
- "mean_delta_norm": 5.5481111892186075e-11,
673
- "max_delta_norm": 6.390629692099026e-11,
674
- "n_active_neurons_bmu": 10,
675
- "n_dead_neurons_bmu": 854,
676
- "neuron_activation_rate": 0.011574074074074073,
677
- "current_hyp_train_steps": 30,
678
- "total_hyp_steps_executed": 0,
679
- "n_train_hyp_calls": 0
680
- },
681
- {
682
- "step": 28,
683
- "chunk_idx": 4,
684
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
685
- "quantization_error": 0.012031015940010548,
686
- "topological_error": 1.0,
687
- "kaski_lagus_error": 2.3798458777851814,
688
- "explained_variance_share": 0.0,
689
- "overall_health": "critical",
690
- "n_failure_indicators": 3,
691
- "failure_indicators": [
692
- "dead_neuron_rate_high_1.00",
693
- "low_explained_variance_0.00",
694
- "high_topological_error_1.00"
695
- ],
696
- "collapse_severity": "none",
697
- "dead_neuron_rate": 0.9976851851851852,
698
- "nan_detected": false,
699
- "nan_reason": null,
700
- "qe_was_nan": false,
701
- "kl_was_nan": false,
702
- "n_hypotheses_active": 0,
703
- "n_hypotheses_total": 16,
704
- "hypothesis_activation_rate": 0.0,
705
- "mean_delta_norm": 6.429341642411046e-10,
706
- "max_delta_norm": 6.918212669404511e-10,
707
- "n_active_neurons_bmu": 2,
708
- "n_dead_neurons_bmu": 862,
709
- "neuron_activation_rate": 0.0023148148148148147,
710
- "current_hyp_train_steps": 30,
711
- "total_hyp_steps_executed": 0,
712
- "n_train_hyp_calls": 0
713
- },
714
- {
715
- "step": 35,
716
- "chunk_idx": 5,
717
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
718
- "quantization_error": 0.009746708907186985,
719
- "topological_error": 1.0,
720
- "kaski_lagus_error": 2.0229230836057637,
721
- "explained_variance_share": 0.0,
722
- "overall_health": "critical",
723
- "n_failure_indicators": 3,
724
- "failure_indicators": [
725
- "dead_neuron_rate_high_1.00",
726
- "low_explained_variance_0.00",
727
- "high_topological_error_1.00"
728
- ],
729
- "collapse_severity": "none",
730
- "dead_neuron_rate": 0.9976851851851852,
731
- "nan_detected": false,
732
- "nan_reason": null,
733
- "qe_was_nan": false,
734
- "kl_was_nan": false,
735
- "n_hypotheses_active": 0,
736
- "n_hypotheses_total": 16,
737
- "hypothesis_activation_rate": 0.0,
738
- "mean_delta_norm": 6.375817547532581e-10,
739
- "max_delta_norm": 7.304411520081544e-10,
740
- "n_active_neurons_bmu": 2,
741
- "n_dead_neurons_bmu": 862,
742
- "neuron_activation_rate": 0.0023148148148148147,
743
- "current_hyp_train_steps": 30,
744
- "total_hyp_steps_executed": 0,
745
- "n_train_hyp_calls": 0
746
- }
747
- ],
748
- "som_metrics_final": {
749
- "quantization_error": 0.009746708907186985,
750
- "topological_error": 1.0,
751
- "kaski_lagus_error": 2.0229230836057637,
752
- "explained_variance_share": 0.0,
753
- "topological_collapse": {
754
- "collapsed_to_point": false,
755
- "collapsed_to_line": false,
756
- "effective_rank": 3.9666486969891515,
757
- "singular_values": [
758
- 0.7090448141098022,
759
- 0.6143536567687988,
760
- 0.5655514597892761,
761
- 0.4965478777885437
762
- ],
763
- "severity": "none"
764
- },
765
- "dead_neuron_rate": {
766
- "dead_neuron_rate": 0.9976851851851852,
767
- "n_dead": 862,
768
- "n_active": 2,
769
- "n_total": 864,
770
- "dead_indices": [
771
- [
772
- 0,
773
- 0,
774
- 0,
775
- 0
776
- ],
777
- [
778
- 0,
779
- 0,
780
- 0,
781
- 1
782
- ],
783
- [
784
- 0,
785
- 0,
786
- 0,
787
- 2
788
- ],
789
- [
790
- 0,
791
- 0,
792
- 0,
793
- 3
794
- ],
795
- [
796
- 0,
797
- 0,
798
- 1,
799
- 0
800
- ],
801
- [
802
- 0,
803
- 0,
804
- 1,
805
- 1
806
- ],
807
- [
808
- 0,
809
- 0,
810
- 1,
811
- 2
812
- ],
813
- [
814
- 0,
815
- 0,
816
- 1,
817
- 3
818
- ],
819
- [
820
- 0,
821
- 0,
822
- 2,
823
- 0
824
- ],
825
- [
826
- 0,
827
- 0,
828
- 2,
829
- 1
830
- ],
831
- [
832
- 0,
833
- 0,
834
- 2,
835
- 2
836
- ],
837
- [
838
- 0,
839
- 0,
840
- 2,
841
- 3
842
- ],
843
- [
844
- 0,
845
- 0,
846
- 3,
847
- 0
848
- ],
849
- [
850
- 0,
851
- 0,
852
- 3,
853
- 1
854
- ],
855
- [
856
- 0,
857
- 0,
858
- 3,
859
- 2
860
- ],
861
- [
862
- 0,
863
- 0,
864
- 3,
865
- 3
866
- ],
867
- [
868
- 0,
869
- 0,
870
- 4,
871
- 0
872
- ],
873
- [
874
- 0,
875
- 0,
876
- 4,
877
- 1
878
- ],
879
- [
880
- 0,
881
- 0,
882
- 4,
883
- 2
884
- ],
885
- [
886
- 0,
887
- 0,
888
- 4,
889
- 3
890
- ],
891
- [
892
- 0,
893
- 0,
894
- 5,
895
- 0
896
- ],
897
- [
898
- 0,
899
- 0,
900
- 5,
901
- 1
902
- ],
903
- [
904
- 0,
905
- 0,
906
- 5,
907
- 2
908
- ],
909
- [
910
- 0,
911
- 0,
912
- 5,
913
- 3
914
- ],
915
- [
916
- 0,
917
- 1,
918
- 0,
919
- 0
920
- ],
921
- [
922
- 0,
923
- 1,
924
- 0,
925
- 1
926
- ],
927
- [
928
- 0,
929
- 1,
930
- 0,
931
- 2
932
- ],
933
- [
934
- 0,
935
- 1,
936
- 0,
937
- 3
938
- ],
939
- [
940
- 0,
941
- 1,
942
- 1,
943
- 0
944
- ],
945
- [
946
- 0,
947
- 1,
948
- 1,
949
- 1
950
- ],
951
- [
952
- 0,
953
- 1,
954
- 1,
955
- 2
956
- ],
957
- [
958
- 0,
959
- 1,
960
- 1,
961
- 3
962
- ],
963
- [
964
- 0,
965
- 1,
966
- 2,
967
- 0
968
- ],
969
- [
970
- 0,
971
- 1,
972
- 2,
973
- 1
974
- ],
975
- [
976
- 0,
977
- 1,
978
- 2,
979
- 2
980
- ],
981
- [
982
- 0,
983
- 1,
984
- 2,
985
- 3
986
- ],
987
- [
988
- 0,
989
- 1,
990
- 3,
991
- 0
992
- ],
993
- [
994
- 0,
995
- 1,
996
- 3,
997
- 1
998
- ],
999
- [
1000
- 0,
1001
- 1,
1002
- 3,
1003
- 2
1004
- ],
1005
- [
1006
- 0,
1007
- 1,
1008
- 3,
1009
- 3
1010
- ],
1011
- [
1012
- 0,
1013
- 1,
1014
- 4,
1015
- 0
1016
- ],
1017
- [
1018
- 0,
1019
- 1,
1020
- 4,
1021
- 1
1022
- ],
1023
- [
1024
- 0,
1025
- 1,
1026
- 4,
1027
- 2
1028
- ],
1029
- [
1030
- 0,
1031
- 1,
1032
- 4,
1033
- 3
1034
- ],
1035
- [
1036
- 0,
1037
- 1,
1038
- 5,
1039
- 0
1040
- ],
1041
- [
1042
- 0,
1043
- 1,
1044
- 5,
1045
- 1
1046
- ],
1047
- [
1048
- 0,
1049
- 1,
1050
- 5,
1051
- 2
1052
- ],
1053
- [
1054
- 0,
1055
- 1,
1056
- 5,
1057
- 3
1058
- ],
1059
- [
1060
- 0,
1061
- 2,
1062
- 0,
1063
- 0
1064
- ],
1065
- [
1066
- 0,
1067
- 2,
1068
- 0,
1069
- 1
1070
- ]
1071
- ]
1072
- },
1073
- "qe_stagnation": {
1074
- "is_stagnant": false,
1075
- "current_qe": 0.009746708907186985,
1076
- "max_qe": 0.009746708907186985,
1077
- "slope": 0.0,
1078
- "severity": "none",
1079
- "n_epochs": 0
1080
- },
1081
- "neighborhood_crossing": {
1082
- "detected": false,
1083
- "te_initial_mean": 0.0,
1084
- "te_final_mean": 0.0,
1085
- "te_initial_std": 0.0,
1086
- "te_final_std": 0.0,
1087
- "std_ratio": 0.0,
1088
- "is_oscillating": false,
1089
- "is_growing": false,
1090
- "severity": "none",
1091
- "n_epochs": 0
1092
- },
1093
- "failure_indicators": [
1094
- "dead_neuron_rate_high_1.00",
1095
- "low_explained_variance_0.00",
1096
- "high_topological_error_1.00"
1097
- ],
1098
- "overall_health": "critical",
1099
- "n_failure_indicators": 3
1100
- },
1101
- "som_metric_history": {
1102
- "epoch": 6,
1103
- "qe_history": [
1104
- 2.26032170758117e-05,
1105
- 0.000569911440834403,
1106
- 0.005070194136351347,
1107
- 0.012031015940010548,
1108
- 0.009746708907186985,
1109
- 0.009746708907186985
1110
- ],
1111
- "te_history": [
1112
- 0.880000002682209,
1113
- 0.9140625,
1114
- 0.984375,
1115
- 1.0,
1116
- 1.0,
1117
- 1.0
1118
- ],
1119
- "kl_history": [
1120
- 0.4445206419101888,
1121
- 0.5460798889633685,
1122
- 1.2844052385351477,
1123
- 2.3798458777851814,
1124
- 2.0229230836057637,
1125
- 2.0229230836057637
1126
- ],
1127
- "var_explained_history": [
1128
- 0.999451068570896,
1129
- 0.928539884025705,
1130
- 0.05886936612972116,
1131
- 0.0,
1132
- 0.0,
1133
- 0.0
1134
- ],
1135
- "dead_neuron_rate_history": [
1136
- 0.8900462962962963,
1137
- 0.9456018518518519,
1138
- 0.9884259259259259,
1139
- 0.9976851851851852,
1140
- 0.9976851851851852,
1141
- 0.9976851851851852
1142
- ]
1143
- },
1144
- "final_state": {
1145
- "version": "V2-dynamic",
1146
- "n_hypotheses": 16,
1147
- "n_hypotheses_active": 16,
1148
- "max_n_hypotheses": 32,
1149
- "n_trials": 3,
1150
- "hyp_train_steps": 30,
1151
- "hyp_lr": 0.0001,
1152
- "delta_scale": 0.009999999776482582,
1153
- "n_generators": 32,
1154
- "punishment_count": 0,
1155
- "success_count": 0,
1156
- "training_ready": true,
1157
- "classifier_trained": false,
1158
- "ewc_reference_set": false,
1159
- "buffer_size": 128,
1160
- "total_hyp_steps_executed": 0,
1161
- "n_train_hyp_calls": 0,
1162
- "dynamic_adaptation": {
1163
- "loss_history_len": 0,
1164
- "loss_stats": {
1165
- "slope": 0.0,
1166
- "volatility": 0.0,
1167
- "mean": 0.0,
1168
- "n": 0
1169
- },
1170
- "punishment_rate": 0.0,
1171
- "punishment_window_size": 0,
1172
- "n_adaptations": 0,
1173
- "limits": {
1174
- "min_n_hypotheses": 4,
1175
- "max_n_hypotheses": 32,
1176
- "min_n_trials": 1,
1177
- "max_n_trials": 6,
1178
- "min_hyp_train_steps": 10,
1179
- "max_hyp_train_steps": 80
1180
- },
1181
- "last_5_adaptations": []
1182
- }
1183
- },
1184
- "auto_adjust_log": [
1185
- {
1186
- "step": 7,
1187
- "chunk_idx": 1,
1188
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
1189
- "phase": "CONHECIMENTO",
1190
- "actions": [
1191
- "te_high_boost: σ+0.352 (te=0.880)",
1192
- "kl_high: kl=0.445 (covered by qe/te boosts)",
1193
- "conscience_auto_adjust: γ 0.103 → 0.099 (r=0.848)",
1194
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=5.4837"
1195
- ],
1196
- "boosts": {
1197
- "alpha0_boost": 1.0,
1198
- "sigma0_boost": 1.3520000010728837
1199
- },
1200
- "n_actions": 4
1201
- },
1202
- {
1203
- "step": 14,
1204
- "chunk_idx": 2,
1205
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
1206
- "phase": "CONHECIMENTO",
1207
- "actions": [
1208
- "te_high_boost: σ+0.366 (te=0.914)",
1209
- "kl_high: kl=0.546 (covered by qe/te boosts)",
1210
- "conscience_auto_adjust: γ 0.021 → 0.021 (r=0.856)",
1211
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=8.8507"
1212
- ],
1213
- "boosts": {
1214
- "alpha0_boost": 1.0,
1215
- "sigma0_boost": 1.7176250010728837
1216
- },
1217
- "n_actions": 4
1218
- },
1219
- {
1220
- "step": 21,
1221
- "chunk_idx": 3,
1222
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
1223
- "phase": "CONHECIMENTO",
1224
- "actions": [
1225
- "te_high_boost: σ+0.394 (te=0.984)",
1226
- "kl_high: kl=1.284 (covered by qe/te boosts)",
1227
- "ve_low_revive: n_revived=124 (ve=0.059)",
1228
- "conscience_auto_adjust: γ 0.021 → 0.021 (r=0.856)",
1229
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=12.0000"
1230
- ],
1231
- "boosts": {
1232
- "alpha0_boost": 1.0,
1233
- "sigma0_boost": 2.0
1234
- },
1235
- "n_actions": 5
1236
- },
1237
- {
1238
- "step": 28,
1239
- "chunk_idx": 4,
1240
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
1241
- "phase": "CONHECIMENTO",
1242
- "actions": [
1243
- "te_high_boost: σ+0.400 (te=1.000)",
1244
- "kl_high: kl=2.380 (covered by qe/te boosts)",
1245
- "ve_low_revive: n_revived=123 (ve=0.000)",
1246
- "conscience_auto_adjust: γ 0.020 → 0.020 (r=0.858)"
1247
- ],
1248
- "boosts": {
1249
- "alpha0_boost": 1.0,
1250
- "sigma0_boost": 2.0
1251
- },
1252
- "n_actions": 4
1253
- },
1254
- {
1255
- "step": 35,
1256
- "chunk_idx": 5,
1257
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
1258
- "phase": "CONHECIMENTO",
1259
- "actions": [
1260
- "te_high_boost: σ+0.400 (te=1.000)",
1261
- "kl_high: kl=2.023 (covered by qe/te boosts)",
1262
- "ve_low_revive: n_revived=121 (ve=0.000)",
1263
- "conscience_auto_adjust: γ 0.020 → 0.020 (r=0.860)"
1264
- ],
1265
- "boosts": {
1266
- "alpha0_boost": 1.0,
1267
- "sigma0_boost": 2.0
1268
- },
1269
- "n_actions": 4
1270
- }
1271
- ],
1272
- "auto_adjust_state": {
1273
- "alpha0_boost": 1.0,
1274
- "sigma0_boost": 2.0,
1275
- "consecutive_collapse_point": 0,
1276
- "consecutive_qe_stagnant_severe": 0,
1277
- "consecutive_dead_rate_critical": 5,
1278
- "consecutive_nan_batches": 0,
1279
- "stop_training": true,
1280
- "stop_reason": "dead_rate_critical_consecutive=5",
1281
- "n_actions_total": 21,
1282
- "n_actions_logged": 5,
1283
- "recent_actions": [
1284
- {
1285
- "batch_idx": 1,
1286
- "actions": [
1287
- "te_high_boost: σ+0.352 (te=0.880)",
1288
- "kl_high: kl=0.445 (covered by qe/te boosts)",
1289
- "conscience_auto_adjust: γ 0.103 → 0.099 (r=0.848)",
1290
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=5.4837"
1291
- ],
1292
- "metrics_snapshot": {
1293
- "qe": 2.26032170758117e-05,
1294
- "te": 0.880000002682209,
1295
- "kl": 0.4445206419101888,
1296
- "ve": 0.999451068570896,
1297
- "dead_rate": 0.8900462962962963,
1298
- "collapse_severity": "line",
1299
- "qe_stagnant": false,
1300
- "crossing_detected": false,
1301
- "nan_detected": false
1302
- },
1303
- "boosts": {
1304
- "alpha0_boost": 1.0,
1305
- "sigma0_boost": 1.3520000010728837
1306
- },
1307
- "stop_training": false
1308
- },
1309
- {
1310
- "batch_idx": 2,
1311
- "actions": [
1312
- "te_high_boost: σ+0.366 (te=0.914)",
1313
- "kl_high: kl=0.546 (covered by qe/te boosts)",
1314
- "conscience_auto_adjust: γ 0.021 → 0.021 (r=0.856)",
1315
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=8.8507"
1316
- ],
1317
- "metrics_snapshot": {
1318
- "qe": 0.000569911440834403,
1319
- "te": 0.9140625,
1320
- "kl": 0.5460798889633685,
1321
- "ve": 0.928539884025705,
1322
- "dead_rate": 0.9456018518518519,
1323
- "collapse_severity": "line",
1324
- "qe_stagnant": false,
1325
- "crossing_detected": false,
1326
- "nan_detected": false
1327
- },
1328
- "boosts": {
1329
- "alpha0_boost": 1.0,
1330
- "sigma0_boost": 1.7176250010728837
1331
- },
1332
- "stop_training": false
1333
- },
1334
- {
1335
- "batch_idx": 3,
1336
- "actions": [
1337
- "te_high_boost: σ+0.394 (te=0.984)",
1338
- "kl_high: kl=1.284 (covered by qe/te boosts)",
1339
- "ve_low_revive: n_revived=124 (ve=0.059)",
1340
- "conscience_auto_adjust: γ 0.021 → 0.021 (r=0.856)",
1341
- "boosts_applied: α₀_eff=0.5000, σ₀_eff=12.0000"
1342
- ],
1343
- "metrics_snapshot": {
1344
- "qe": 0.005070194136351347,
1345
- "te": 0.984375,
1346
- "kl": 1.2844052385351477,
1347
- "ve": 0.05886936612972116,
1348
- "dead_rate": 0.9884259259259259,
1349
- "collapse_severity": "line",
1350
- "qe_stagnant": false,
1351
- "crossing_detected": false,
1352
- "nan_detected": false
1353
- },
1354
- "boosts": {
1355
- "alpha0_boost": 1.0,
1356
- "sigma0_boost": 2.0
1357
- },
1358
- "stop_training": false
1359
- },
1360
- {
1361
- "batch_idx": 4,
1362
- "actions": [
1363
- "te_high_boost: σ+0.400 (te=1.000)",
1364
- "kl_high: kl=2.380 (covered by qe/te boosts)",
1365
- "ve_low_revive: n_revived=123 (ve=0.000)",
1366
- "conscience_auto_adjust: γ 0.020 → 0.020 (r=0.858)"
1367
- ],
1368
- "metrics_snapshot": {
1369
- "qe": 0.012031015940010548,
1370
- "te": 1.0,
1371
- "kl": 2.3798458777851814,
1372
- "ve": 0.0,
1373
- "dead_rate": 0.9976851851851852,
1374
- "collapse_severity": "none",
1375
- "qe_stagnant": false,
1376
- "crossing_detected": false,
1377
- "nan_detected": false
1378
- },
1379
- "boosts": {
1380
- "alpha0_boost": 1.0,
1381
- "sigma0_boost": 2.0
1382
- },
1383
- "stop_training": false
1384
- },
1385
- {
1386
- "batch_idx": 5,
1387
- "actions": [
1388
- "te_high_boost: σ+0.400 (te=1.000)",
1389
- "kl_high: kl=2.023 (covered by qe/te boosts)",
1390
- "ve_low_revive: n_revived=121 (ve=0.000)",
1391
- "conscience_auto_adjust: γ 0.020 → 0.020 (r=0.860)"
1392
- ],
1393
- "metrics_snapshot": {
1394
- "qe": 0.009746708907186985,
1395
- "te": 1.0,
1396
- "kl": 2.0229230836057637,
1397
- "ve": 0.0,
1398
- "dead_rate": 0.9976851851851852,
1399
- "collapse_severity": "none",
1400
- "qe_stagnant": false,
1401
- "crossing_detected": false,
1402
- "nan_detected": false
1403
- },
1404
- "boosts": {
1405
- "alpha0_boost": 1.0,
1406
- "sigma0_boost": 2.0
1407
- },
1408
- "stop_training": true
1409
- }
1410
- ]
1411
- },
1412
- "stop_training_reason": "dead_rate_critical_consecutive=5"
1413
- }
1414
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v6_5_v2_predict_fix_eval.json DELETED
@@ -1,84 +0,0 @@
1
- {
2
- "evaluation": "predict_fix_v65_v2",
3
- "user_requirement": "os strings 'gato' e 'cachorro' são fixos quando deveriam ser extrações variáveis e flexíveis de rótulos proveniente de dados dos datasets anteriormente treinados",
4
- "n_test_queries": 6,
5
- "results": [
6
- {
7
- "query": "o gato dorme na cama",
8
- "prediction": "punctuated",
9
- "probability": 1.0,
10
- "is_gato_hardcoded": false,
11
- "is_cachorro_hardcoded": false,
12
- "is_registry_label": true,
13
- "is_default_label": false
14
- },
15
- {
16
- "query": "calcule dois mais dois",
17
- "prediction": "punctuated",
18
- "probability": 1.0,
19
- "is_gato_hardcoded": false,
20
- "is_cachorro_hardcoded": false,
21
- "is_registry_label": true,
22
- "is_default_label": false
23
- },
24
- {
25
- "query": "qual é a capital do brasil",
26
- "prediction": "punctuated",
27
- "probability": 1.0,
28
- "is_gato_hardcoded": false,
29
- "is_cachorro_hardcoded": false,
30
- "is_registry_label": true,
31
- "is_default_label": false
32
- },
33
- {
34
- "query": "explique o que é uma rede neural",
35
- "prediction": "punctuated",
36
- "probability": 1.0,
37
- "is_gato_hardcoded": false,
38
- "is_cachorro_hardcoded": false,
39
- "is_registry_label": true,
40
- "is_default_label": false
41
- },
42
- {
43
- "query": "olá como você está",
44
- "prediction": "punctuated",
45
- "probability": 1.0,
46
- "is_gato_hardcoded": false,
47
- "is_cachorro_hardcoded": false,
48
- "is_registry_label": true,
49
- "is_default_label": false
50
- },
51
- {
52
- "query": "traduza hello para portugues",
53
- "prediction": "punctuated",
54
- "probability": 1.0,
55
- "is_gato_hardcoded": false,
56
- "is_cachorro_hardcoded": false,
57
- "is_registry_label": true,
58
- "is_default_label": false
59
- }
60
- ],
61
- "per_dataset_results": [
62
- {
63
- "dataset": "dominguesm/restore-punctuation-ptbr-dataset",
64
- "expected_labels": [
65
- "unpunctuated",
66
- "punctuated"
67
- ],
68
- "prediction": "punctuated",
69
- "valid_for_dataset": true
70
- }
71
- ],
72
- "summary": {
73
- "n_returns_gato": 0,
74
- "n_returns_cachorro": 0,
75
- "n_returns_registry_label": 6,
76
- "n_returns_default_label": 0,
77
- "hardcoded_bug_present": false,
78
- "predict_fix_verified": true
79
- },
80
- "quality_assessment": {
81
- "fix_status": "PASS",
82
- "note": "predict() não retorna mais 'gato'/'cachorro' fixos — usa label_registry dinâmico."
83
- }
84
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v6_5_v2_punicão_report.json DELETED
@@ -1,1199 +0,0 @@
1
- {
2
- "version": "V6.5-V2-dynamic-punicão",
3
- "timestamp": "2026-08-08T21:32:29.242618",
4
- "loaded_from_fase1": "/home/z/my-project/BiGRU_T_version/v6_5_v2_model_states.pt",
5
- "fase1_total_samples": 3300,
6
- "fase2_total_samples": 1000,
7
- "fase2_meta_atingida": true,
8
- "fase2_elapsed_s": 135.41348695755005,
9
- "punishment_events": [
10
- {
11
- "step": 0,
12
- "action": "train_hypotheses_and_activate",
13
- "accuracy": 0.5,
14
- "punishment_count": 1,
15
- "cycle_completed": false
16
- },
17
- {
18
- "step": 1,
19
- "action": "apply_best_delta_and_consolidate",
20
- "accuracy": 0.625,
21
- "punishment_count": 0,
22
- "cycle_completed": true
23
- },
24
- {
25
- "step": 2,
26
- "action": "train_hypotheses_and_activate",
27
- "accuracy": 0.5416666666666666,
28
- "punishment_count": 1,
29
- "cycle_completed": false
30
- },
31
- {
32
- "step": 3,
33
- "action": "apply_best_delta_and_consolidate",
34
- "accuracy": 0.546875,
35
- "punishment_count": 0,
36
- "cycle_completed": true
37
- },
38
- {
39
- "step": 4,
40
- "action": "train_hypotheses_and_activate",
41
- "accuracy": 0.5625,
42
- "punishment_count": 1,
43
- "cycle_completed": false
44
- },
45
- {
46
- "step": 5,
47
- "action": "apply_best_delta_and_consolidate",
48
- "accuracy": 0.5520833333333334,
49
- "punishment_count": 0,
50
- "cycle_completed": true
51
- },
52
- {
53
- "step": 7,
54
- "action": "train_hypotheses_and_activate",
55
- "accuracy": 0.5517241379310345,
56
- "punishment_count": 1,
57
- "cycle_completed": false
58
- },
59
- {
60
- "step": 8,
61
- "action": "apply_best_delta_and_consolidate",
62
- "accuracy": 0.5454545454545454,
63
- "punishment_count": 0,
64
- "cycle_completed": true
65
- },
66
- {
67
- "step": 9,
68
- "action": "train_hypotheses_and_activate",
69
- "accuracy": 0.5337837837837838,
70
- "punishment_count": 1,
71
- "cycle_completed": false
72
- },
73
- {
74
- "step": 10,
75
- "action": "apply_best_delta_and_consolidate",
76
- "accuracy": 0.5426829268292683,
77
- "punishment_count": 0,
78
- "cycle_completed": true
79
- },
80
- {
81
- "step": 11,
82
- "action": "train_hypotheses_and_activate",
83
- "accuracy": 0.5388888888888889,
84
- "punishment_count": 1,
85
- "cycle_completed": false
86
- },
87
- {
88
- "step": 12,
89
- "action": "apply_best_delta_and_consolidate",
90
- "accuracy": 0.5204081632653061,
91
- "punishment_count": 0,
92
- "cycle_completed": true
93
- },
94
- {
95
- "step": 14,
96
- "action": "train_hypotheses_and_activate",
97
- "accuracy": 0.5092592592592593,
98
- "punishment_count": 1,
99
- "cycle_completed": false
100
- },
101
- {
102
- "step": 15,
103
- "action": "apply_best_delta_and_consolidate",
104
- "accuracy": 0.5043103448275862,
105
- "punishment_count": 0,
106
- "cycle_completed": true
107
- },
108
- {
109
- "step": 16,
110
- "action": "train_hypotheses_and_activate",
111
- "accuracy": 0.5080645161290323,
112
- "punishment_count": 1,
113
- "cycle_completed": false
114
- },
115
- {
116
- "step": 17,
117
- "action": "apply_best_delta_and_consolidate",
118
- "accuracy": 0.5,
119
- "punishment_count": 0,
120
- "cycle_completed": true
121
- },
122
- {
123
- "step": 18,
124
- "action": "train_hypotheses_and_activate",
125
- "accuracy": 0.5183823529411765,
126
- "punishment_count": 1,
127
- "cycle_completed": false
128
- },
129
- {
130
- "step": 19,
131
- "action": "apply_best_delta_and_consolidate",
132
- "accuracy": 0.5173611111111112,
133
- "punishment_count": 0,
134
- "cycle_completed": true
135
- },
136
- {
137
- "step": 21,
138
- "action": "train_hypotheses_and_activate",
139
- "accuracy": 0.5110294117647058,
140
- "punishment_count": 1,
141
- "cycle_completed": false
142
- },
143
- {
144
- "step": 22,
145
- "action": "apply_best_delta_and_consolidate",
146
- "accuracy": 0.5138888888888888,
147
- "punishment_count": 0,
148
- "cycle_completed": true
149
- },
150
- {
151
- "step": 23,
152
- "action": "train_hypotheses_and_activate",
153
- "accuracy": 0.5036764705882353,
154
- "punishment_count": 1,
155
- "cycle_completed": false
156
- },
157
- {
158
- "step": 24,
159
- "action": "apply_best_delta_and_consolidate",
160
- "accuracy": 0.4930555555555556,
161
- "punishment_count": 0,
162
- "cycle_completed": true
163
- },
164
- {
165
- "step": 25,
166
- "action": "train_hypotheses_and_activate",
167
- "accuracy": 0.4889705882352941,
168
- "punishment_count": 1,
169
- "cycle_completed": false
170
- },
171
- {
172
- "step": 26,
173
- "action": "apply_best_delta_and_consolidate",
174
- "accuracy": 0.4756944444444444,
175
- "punishment_count": 0,
176
- "cycle_completed": true
177
- },
178
- {
179
- "step": 28,
180
- "action": "train_hypotheses_and_activate",
181
- "accuracy": 0.47794117647058826,
182
- "punishment_count": 1,
183
- "cycle_completed": false
184
- },
185
- {
186
- "step": 29,
187
- "action": "apply_best_delta_and_consolidate",
188
- "accuracy": 0.4895833333333333,
189
- "punishment_count": 0,
190
- "cycle_completed": true
191
- },
192
- {
193
- "step": 30,
194
- "action": "train_hypotheses_and_activate",
195
- "accuracy": 0.4742647058823529,
196
- "punishment_count": 1,
197
- "cycle_completed": false
198
- },
199
- {
200
- "step": 31,
201
- "action": "apply_best_delta_and_consolidate",
202
- "accuracy": 0.4826388888888889,
203
- "punishment_count": 0,
204
- "cycle_completed": true
205
- },
206
- {
207
- "step": 32,
208
- "action": "train_hypotheses_and_activate",
209
- "accuracy": 0.5073529411764706,
210
- "punishment_count": 1,
211
- "cycle_completed": false
212
- },
213
- {
214
- "step": 33,
215
- "action": "apply_best_delta_and_consolidate",
216
- "accuracy": 0.5138888888888888,
217
- "punishment_count": 0,
218
- "cycle_completed": true
219
- },
220
- {
221
- "step": 35,
222
- "action": "train_hypotheses_and_activate",
223
- "accuracy": 0.5110294117647058,
224
- "punishment_count": 1,
225
- "cycle_completed": false
226
- },
227
- {
228
- "step": 36,
229
- "action": "apply_best_delta_and_consolidate",
230
- "accuracy": 0.5104166666666666,
231
- "punishment_count": 0,
232
- "cycle_completed": true
233
- },
234
- {
235
- "step": 37,
236
- "action": "train_hypotheses_and_activate",
237
- "accuracy": 0.47794117647058826,
238
- "punishment_count": 1,
239
- "cycle_completed": false
240
- },
241
- {
242
- "step": 38,
243
- "action": "apply_best_delta_and_consolidate",
244
- "accuracy": 0.4791666666666667,
245
- "punishment_count": 0,
246
- "cycle_completed": true
247
- },
248
- {
249
- "step": 39,
250
- "action": "train_hypotheses_and_activate",
251
- "accuracy": 0.47058823529411764,
252
- "punishment_count": 1,
253
- "cycle_completed": false
254
- },
255
- {
256
- "step": 40,
257
- "action": "apply_best_delta_and_consolidate",
258
- "accuracy": 0.4930555555555556,
259
- "punishment_count": 0,
260
- "cycle_completed": true
261
- },
262
- {
263
- "step": 42,
264
- "action": "train_hypotheses_and_activate",
265
- "accuracy": 0.4889705882352941,
266
- "punishment_count": 1,
267
- "cycle_completed": false
268
- },
269
- {
270
- "step": 43,
271
- "action": "apply_best_delta_and_consolidate",
272
- "accuracy": 0.4965277777777778,
273
- "punishment_count": 0,
274
- "cycle_completed": true
275
- },
276
- {
277
- "step": 44,
278
- "action": "train_hypotheses_and_activate",
279
- "accuracy": 0.5110294117647058,
280
- "punishment_count": 1,
281
- "cycle_completed": false
282
- },
283
- {
284
- "step": 45,
285
- "action": "apply_best_delta_and_consolidate",
286
- "accuracy": 0.5138888888888888,
287
- "punishment_count": 0,
288
- "cycle_completed": true
289
- },
290
- {
291
- "step": 46,
292
- "action": "train_hypotheses_and_activate",
293
- "accuracy": 0.5367647058823529,
294
- "punishment_count": 1,
295
- "cycle_completed": false
296
- },
297
- {
298
- "step": 47,
299
- "action": "apply_best_delta_and_consolidate",
300
- "accuracy": 0.5208333333333334,
301
- "punishment_count": 0,
302
- "cycle_completed": true
303
- },
304
- {
305
- "step": 49,
306
- "action": "train_hypotheses_and_activate",
307
- "accuracy": 0.5110294117647058,
308
- "punishment_count": 1,
309
- "cycle_completed": false
310
- },
311
- {
312
- "step": 50,
313
- "action": "apply_best_delta_and_consolidate",
314
- "accuracy": 0.5208333333333334,
315
- "punishment_count": 0,
316
- "cycle_completed": true
317
- },
318
- {
319
- "step": 51,
320
- "action": "train_hypotheses_and_activate",
321
- "accuracy": 0.5183823529411765,
322
- "punishment_count": 1,
323
- "cycle_completed": false
324
- },
325
- {
326
- "step": 52,
327
- "action": "apply_best_delta_and_consolidate",
328
- "accuracy": 0.5173611111111112,
329
- "punishment_count": 0,
330
- "cycle_completed": true
331
- },
332
- {
333
- "step": 53,
334
- "action": "train_hypotheses_and_activate",
335
- "accuracy": 0.5073529411764706,
336
- "punishment_count": 1,
337
- "cycle_completed": false
338
- },
339
- {
340
- "step": 54,
341
- "action": "apply_best_delta_and_consolidate",
342
- "accuracy": 0.5104166666666666,
343
- "punishment_count": 0,
344
- "cycle_completed": true
345
- },
346
- {
347
- "step": 56,
348
- "action": "train_hypotheses_and_activate",
349
- "accuracy": 0.5110294117647058,
350
- "punishment_count": 1,
351
- "cycle_completed": false
352
- },
353
- {
354
- "step": 57,
355
- "action": "apply_best_delta_and_consolidate",
356
- "accuracy": 0.4965277777777778,
357
- "punishment_count": 0,
358
- "cycle_completed": true
359
- },
360
- {
361
- "step": 58,
362
- "action": "train_hypotheses_and_activate",
363
- "accuracy": 0.5147058823529411,
364
- "punishment_count": 1,
365
- "cycle_completed": false
366
- },
367
- {
368
- "step": 59,
369
- "action": "apply_best_delta_and_consolidate",
370
- "accuracy": 0.5104166666666666,
371
- "punishment_count": 0,
372
- "cycle_completed": true
373
- },
374
- {
375
- "step": 60,
376
- "action": "train_hypotheses_and_activate",
377
- "accuracy": 0.4963235294117647,
378
- "punishment_count": 1,
379
- "cycle_completed": false
380
- },
381
- {
382
- "step": 61,
383
- "action": "apply_best_delta_and_consolidate",
384
- "accuracy": 0.4895833333333333,
385
- "punishment_count": 0,
386
- "cycle_completed": true
387
- },
388
- {
389
- "step": 63,
390
- "action": "train_hypotheses_and_activate",
391
- "accuracy": 0.46691176470588236,
392
- "punishment_count": 1,
393
- "cycle_completed": false
394
- },
395
- {
396
- "step": 64,
397
- "action": "apply_best_delta_and_consolidate",
398
- "accuracy": 0.4722222222222222,
399
- "punishment_count": 0,
400
- "cycle_completed": true
401
- },
402
- {
403
- "step": 65,
404
- "action": "train_hypotheses_and_activate",
405
- "accuracy": 0.45588235294117646,
406
- "punishment_count": 1,
407
- "cycle_completed": false
408
- },
409
- {
410
- "step": 66,
411
- "action": "apply_best_delta_and_consolidate",
412
- "accuracy": 0.4583333333333333,
413
- "punishment_count": 0,
414
- "cycle_completed": true
415
- },
416
- {
417
- "step": 67,
418
- "action": "train_hypotheses_and_activate",
419
- "accuracy": 0.4632352941176471,
420
- "punishment_count": 1,
421
- "cycle_completed": false
422
- },
423
- {
424
- "step": 68,
425
- "action": "apply_best_delta_and_consolidate",
426
- "accuracy": 0.4722222222222222,
427
- "punishment_count": 0,
428
- "cycle_completed": true
429
- }
430
- ],
431
- "hypotheses_trainings": [
432
- {
433
- "step": 0,
434
- "loss_initial": NaN,
435
- "loss_final": NaN,
436
- "delta_scale": 0.008179070428013802
437
- },
438
- {
439
- "step": 2,
440
- "loss_initial": NaN,
441
- "loss_final": NaN,
442
- "delta_scale": 0.00668971985578537
443
- },
444
- {
445
- "step": 4,
446
- "loss_initial": NaN,
447
- "loss_final": NaN,
448
- "delta_scale": 0.005471568554639816
449
- },
450
- {
451
- "step": 7,
452
- "loss_initial": NaN,
453
- "loss_final": NaN,
454
- "delta_scale": 0.00447523407638073
455
- },
456
- {
457
- "step": 9,
458
- "loss_initial": NaN,
459
- "loss_final": NaN,
460
- "delta_scale": 0.003660326125100255
461
- },
462
- {
463
- "step": 11,
464
- "loss_initial": NaN,
465
- "loss_final": NaN,
466
- "delta_scale": 0.0029938064981251955
467
- },
468
- {
469
- "step": 14,
470
- "loss_initial": NaN,
471
- "loss_final": NaN,
472
- "delta_scale": 0.002448655664920807
473
- },
474
- {
475
- "step": 16,
476
- "loss_initial": NaN,
477
- "loss_final": NaN,
478
- "delta_scale": 0.0020027728751301765
479
- },
480
- {
481
- "step": 18,
482
- "loss_initial": NaN,
483
- "loss_final": NaN,
484
- "delta_scale": 0.0016380823217332363
485
- },
486
- {
487
- "step": 21,
488
- "loss_initial": NaN,
489
- "loss_final": NaN,
490
- "delta_scale": 0.0013397991424426436
491
- },
492
- {
493
- "step": 23,
494
- "loss_initial": NaN,
495
- "loss_final": NaN,
496
- "delta_scale": 0.0010958312777802348
497
- },
498
- {
499
- "step": 25,
500
- "loss_initial": NaN,
501
- "loss_final": NaN,
502
- "delta_scale": 0.0010000000474974513
503
- },
504
- {
505
- "step": 28,
506
- "loss_initial": NaN,
507
- "loss_final": NaN,
508
- "delta_scale": 0.0010000000474974513
509
- },
510
- {
511
- "step": 30,
512
- "loss_initial": NaN,
513
- "loss_final": NaN,
514
- "delta_scale": 0.0010000000474974513
515
- },
516
- {
517
- "step": 32,
518
- "loss_initial": NaN,
519
- "loss_final": NaN,
520
- "delta_scale": 0.0010000000474974513
521
- },
522
- {
523
- "step": 35,
524
- "loss_initial": NaN,
525
- "loss_final": NaN,
526
- "delta_scale": 0.0010000000474974513
527
- },
528
- {
529
- "step": 37,
530
- "loss_initial": NaN,
531
- "loss_final": NaN,
532
- "delta_scale": 0.0010000000474974513
533
- },
534
- {
535
- "step": 39,
536
- "loss_initial": NaN,
537
- "loss_final": NaN,
538
- "delta_scale": 0.0010000000474974513
539
- },
540
- {
541
- "step": 42,
542
- "loss_initial": NaN,
543
- "loss_final": NaN,
544
- "delta_scale": 0.0010000000474974513
545
- },
546
- {
547
- "step": 44,
548
- "loss_initial": NaN,
549
- "loss_final": NaN,
550
- "delta_scale": 0.0010000000474974513
551
- },
552
- {
553
- "step": 46,
554
- "loss_initial": NaN,
555
- "loss_final": NaN,
556
- "delta_scale": 0.0010000000474974513
557
- },
558
- {
559
- "step": 49,
560
- "loss_initial": NaN,
561
- "loss_final": NaN,
562
- "delta_scale": 0.0010000000474974513
563
- },
564
- {
565
- "step": 51,
566
- "loss_initial": NaN,
567
- "loss_final": NaN,
568
- "delta_scale": 0.0010000000474974513
569
- },
570
- {
571
- "step": 53,
572
- "loss_initial": NaN,
573
- "loss_final": NaN,
574
- "delta_scale": 0.0010000000474974513
575
- },
576
- {
577
- "step": 56,
578
- "loss_initial": NaN,
579
- "loss_final": NaN,
580
- "delta_scale": 0.0010000000474974513
581
- },
582
- {
583
- "step": 58,
584
- "loss_initial": NaN,
585
- "loss_final": NaN,
586
- "delta_scale": 0.0010000000474974513
587
- },
588
- {
589
- "step": 60,
590
- "loss_initial": NaN,
591
- "loss_final": NaN,
592
- "delta_scale": 0.0010000000474974513
593
- },
594
- {
595
- "step": 63,
596
- "loss_initial": NaN,
597
- "loss_final": NaN,
598
- "delta_scale": 0.0010000000474974513
599
- },
600
- {
601
- "step": 65,
602
- "loss_initial": NaN,
603
- "loss_final": NaN,
604
- "delta_scale": 0.0010000000474974513
605
- },
606
- {
607
- "step": 67,
608
- "loss_initial": NaN,
609
- "loss_final": NaN,
610
- "delta_scale": 0.0010000000474974513
611
- }
612
- ],
613
- "delta_applications": [
614
- {
615
- "step": 1,
616
- "acc_before": 0.625,
617
- "acc_after": 0.625,
618
- "delta_norm": NaN,
619
- "ewc_reference_set": true
620
- },
621
- {
622
- "step": 3,
623
- "acc_before": 0.546875,
624
- "acc_after": 0.546875,
625
- "delta_norm": NaN,
626
- "ewc_reference_set": true
627
- },
628
- {
629
- "step": 5,
630
- "acc_before": 0.5520833333333334,
631
- "acc_after": 0.5520833333333334,
632
- "delta_norm": NaN,
633
- "ewc_reference_set": true
634
- },
635
- {
636
- "step": 8,
637
- "acc_before": 0.5454545454545454,
638
- "acc_after": 0.5454545454545454,
639
- "delta_norm": NaN,
640
- "ewc_reference_set": true
641
- },
642
- {
643
- "step": 10,
644
- "acc_before": 0.5426829268292683,
645
- "acc_after": 0.5426829268292683,
646
- "delta_norm": NaN,
647
- "ewc_reference_set": true
648
- },
649
- {
650
- "step": 12,
651
- "acc_before": 0.5204081632653061,
652
- "acc_after": 0.5204081632653061,
653
- "delta_norm": NaN,
654
- "ewc_reference_set": true
655
- },
656
- {
657
- "step": 15,
658
- "acc_before": 0.5043103448275862,
659
- "acc_after": 0.5043103448275862,
660
- "delta_norm": NaN,
661
- "ewc_reference_set": true
662
- },
663
- {
664
- "step": 17,
665
- "acc_before": 0.5,
666
- "acc_after": 0.5,
667
- "delta_norm": NaN,
668
- "ewc_reference_set": true
669
- },
670
- {
671
- "step": 19,
672
- "acc_before": 0.5173611111111112,
673
- "acc_after": 0.5173611111111112,
674
- "delta_norm": NaN,
675
- "ewc_reference_set": true
676
- },
677
- {
678
- "step": 22,
679
- "acc_before": 0.5138888888888888,
680
- "acc_after": 0.5138888888888888,
681
- "delta_norm": NaN,
682
- "ewc_reference_set": true
683
- },
684
- {
685
- "step": 24,
686
- "acc_before": 0.4930555555555556,
687
- "acc_after": 0.4930555555555556,
688
- "delta_norm": NaN,
689
- "ewc_reference_set": true
690
- },
691
- {
692
- "step": 26,
693
- "acc_before": 0.4756944444444444,
694
- "acc_after": 0.4756944444444444,
695
- "delta_norm": NaN,
696
- "ewc_reference_set": true
697
- },
698
- {
699
- "step": 29,
700
- "acc_before": 0.4895833333333333,
701
- "acc_after": 0.4895833333333333,
702
- "delta_norm": NaN,
703
- "ewc_reference_set": true
704
- },
705
- {
706
- "step": 31,
707
- "acc_before": 0.4826388888888889,
708
- "acc_after": 0.4826388888888889,
709
- "delta_norm": NaN,
710
- "ewc_reference_set": true
711
- },
712
- {
713
- "step": 33,
714
- "acc_before": 0.5138888888888888,
715
- "acc_after": 0.5138888888888888,
716
- "delta_norm": NaN,
717
- "ewc_reference_set": true
718
- },
719
- {
720
- "step": 36,
721
- "acc_before": 0.5104166666666666,
722
- "acc_after": 0.5104166666666666,
723
- "delta_norm": NaN,
724
- "ewc_reference_set": true
725
- },
726
- {
727
- "step": 38,
728
- "acc_before": 0.4791666666666667,
729
- "acc_after": 0.4791666666666667,
730
- "delta_norm": NaN,
731
- "ewc_reference_set": true
732
- },
733
- {
734
- "step": 40,
735
- "acc_before": 0.4930555555555556,
736
- "acc_after": 0.4930555555555556,
737
- "delta_norm": NaN,
738
- "ewc_reference_set": true
739
- },
740
- {
741
- "step": 43,
742
- "acc_before": 0.4965277777777778,
743
- "acc_after": 0.4965277777777778,
744
- "delta_norm": NaN,
745
- "ewc_reference_set": true
746
- },
747
- {
748
- "step": 45,
749
- "acc_before": 0.5138888888888888,
750
- "acc_after": 0.5138888888888888,
751
- "delta_norm": NaN,
752
- "ewc_reference_set": true
753
- },
754
- {
755
- "step": 47,
756
- "acc_before": 0.5208333333333334,
757
- "acc_after": 0.5208333333333334,
758
- "delta_norm": NaN,
759
- "ewc_reference_set": true
760
- },
761
- {
762
- "step": 50,
763
- "acc_before": 0.5208333333333334,
764
- "acc_after": 0.5208333333333334,
765
- "delta_norm": NaN,
766
- "ewc_reference_set": true
767
- },
768
- {
769
- "step": 52,
770
- "acc_before": 0.5173611111111112,
771
- "acc_after": 0.5173611111111112,
772
- "delta_norm": NaN,
773
- "ewc_reference_set": true
774
- },
775
- {
776
- "step": 54,
777
- "acc_before": 0.5104166666666666,
778
- "acc_after": 0.5104166666666666,
779
- "delta_norm": NaN,
780
- "ewc_reference_set": true
781
- },
782
- {
783
- "step": 57,
784
- "acc_before": 0.4965277777777778,
785
- "acc_after": 0.4965277777777778,
786
- "delta_norm": NaN,
787
- "ewc_reference_set": true
788
- },
789
- {
790
- "step": 59,
791
- "acc_before": 0.5104166666666666,
792
- "acc_after": 0.5104166666666666,
793
- "delta_norm": NaN,
794
- "ewc_reference_set": true
795
- },
796
- {
797
- "step": 61,
798
- "acc_before": 0.4895833333333333,
799
- "acc_after": 0.4895833333333333,
800
- "delta_norm": NaN,
801
- "ewc_reference_set": true
802
- },
803
- {
804
- "step": 64,
805
- "acc_before": 0.4722222222222222,
806
- "acc_after": 0.4722222222222222,
807
- "delta_norm": NaN,
808
- "ewc_reference_set": true
809
- },
810
- {
811
- "step": 66,
812
- "acc_before": 0.4583333333333333,
813
- "acc_after": 0.4583333333333333,
814
- "delta_norm": NaN,
815
- "ewc_reference_set": true
816
- },
817
- {
818
- "step": 68,
819
- "acc_before": 0.4722222222222222,
820
- "acc_after": 0.4722222222222222,
821
- "delta_norm": NaN,
822
- "ewc_reference_set": true
823
- }
824
- ],
825
- "accuracies_log": [
826
- {
827
- "step": 40,
828
- "accuracy": 0.48046875,
829
- "action": "apply_best_delta_and_consolidate",
830
- "punishment_count": 0,
831
- "buffer_size": 256
832
- },
833
- {
834
- "step": 41,
835
- "accuracy": 0.4807692307692308,
836
- "action": "none",
837
- "punishment_count": 0,
838
- "buffer_size": 260
839
- },
840
- {
841
- "step": 42,
842
- "accuracy": 0.4889705882352941,
843
- "action": "train_hypotheses_and_activate",
844
- "punishment_count": 1,
845
- "buffer_size": 272
846
- },
847
- {
848
- "step": 43,
849
- "accuracy": 0.5,
850
- "action": "apply_best_delta_and_consolidate",
851
- "punishment_count": 0,
852
- "buffer_size": 256
853
- },
854
- {
855
- "step": 44,
856
- "accuracy": 0.5110294117647058,
857
- "action": "train_hypotheses_and_activate",
858
- "punishment_count": 1,
859
- "buffer_size": 272
860
- },
861
- {
862
- "step": 45,
863
- "accuracy": 0.53515625,
864
- "action": "apply_best_delta_and_consolidate",
865
- "punishment_count": 0,
866
- "buffer_size": 256
867
- },
868
- {
869
- "step": 46,
870
- "accuracy": 0.5367647058823529,
871
- "action": "train_hypotheses_and_activate",
872
- "punishment_count": 1,
873
- "buffer_size": 272
874
- },
875
- {
876
- "step": 47,
877
- "accuracy": 0.51171875,
878
- "action": "apply_best_delta_and_consolidate",
879
- "punishment_count": 0,
880
- "buffer_size": 256
881
- },
882
- {
883
- "step": 48,
884
- "accuracy": 0.5076923076923077,
885
- "action": "none",
886
- "punishment_count": 0,
887
- "buffer_size": 260
888
- },
889
- {
890
- "step": 49,
891
- "accuracy": 0.5110294117647058,
892
- "action": "train_hypotheses_and_activate",
893
- "punishment_count": 1,
894
- "buffer_size": 272
895
- },
896
- {
897
- "step": 50,
898
- "accuracy": 0.515625,
899
- "action": "apply_best_delta_and_consolidate",
900
- "punishment_count": 0,
901
- "buffer_size": 256
902
- },
903
- {
904
- "step": 51,
905
- "accuracy": 0.5183823529411765,
906
- "action": "train_hypotheses_and_activate",
907
- "punishment_count": 1,
908
- "buffer_size": 272
909
- },
910
- {
911
- "step": 52,
912
- "accuracy": 0.51953125,
913
- "action": "apply_best_delta_and_consolidate",
914
- "punishment_count": 0,
915
- "buffer_size": 256
916
- },
917
- {
918
- "step": 53,
919
- "accuracy": 0.5073529411764706,
920
- "action": "train_hypotheses_and_activate",
921
- "punishment_count": 1,
922
- "buffer_size": 272
923
- },
924
- {
925
- "step": 54,
926
- "accuracy": 0.5234375,
927
- "action": "apply_best_delta_and_consolidate",
928
- "punishment_count": 0,
929
- "buffer_size": 256
930
- },
931
- {
932
- "step": 55,
933
- "accuracy": 0.5230769230769231,
934
- "action": "none",
935
- "punishment_count": 0,
936
- "buffer_size": 260
937
- },
938
- {
939
- "step": 56,
940
- "accuracy": 0.5110294117647058,
941
- "action": "train_hypotheses_and_activate",
942
- "punishment_count": 1,
943
- "buffer_size": 272
944
- },
945
- {
946
- "step": 57,
947
- "accuracy": 0.51171875,
948
- "action": "apply_best_delta_and_consolidate",
949
- "punishment_count": 0,
950
- "buffer_size": 256
951
- },
952
- {
953
- "step": 58,
954
- "accuracy": 0.5147058823529411,
955
- "action": "train_hypotheses_and_activate",
956
- "punishment_count": 1,
957
- "buffer_size": 272
958
- },
959
- {
960
- "step": 59,
961
- "accuracy": 0.5,
962
- "action": "apply_best_delta_and_consolidate",
963
- "punishment_count": 0,
964
- "buffer_size": 256
965
- },
966
- {
967
- "step": 60,
968
- "accuracy": 0.4963235294117647,
969
- "action": "train_hypotheses_and_activate",
970
- "punishment_count": 1,
971
- "buffer_size": 272
972
- },
973
- {
974
- "step": 61,
975
- "accuracy": 0.45703125,
976
- "action": "apply_best_delta_and_consolidate",
977
- "punishment_count": 0,
978
- "buffer_size": 256
979
- },
980
- {
981
- "step": 62,
982
- "accuracy": 0.4576923076923077,
983
- "action": "none",
984
- "punishment_count": 0,
985
- "buffer_size": 260
986
- },
987
- {
988
- "step": 63,
989
- "accuracy": 0.46691176470588236,
990
- "action": "train_hypotheses_and_activate",
991
- "punishment_count": 1,
992
- "buffer_size": 272
993
- },
994
- {
995
- "step": 64,
996
- "accuracy": 0.46484375,
997
- "action": "apply_best_delta_and_consolidate",
998
- "punishment_count": 0,
999
- "buffer_size": 256
1000
- },
1001
- {
1002
- "step": 65,
1003
- "accuracy": 0.45588235294117646,
1004
- "action": "train_hypotheses_and_activate",
1005
- "punishment_count": 1,
1006
- "buffer_size": 272
1007
- },
1008
- {
1009
- "step": 66,
1010
- "accuracy": 0.4609375,
1011
- "action": "apply_best_delta_and_consolidate",
1012
- "punishment_count": 0,
1013
- "buffer_size": 256
1014
- },
1015
- {
1016
- "step": 67,
1017
- "accuracy": 0.4632352941176471,
1018
- "action": "train_hypotheses_and_activate",
1019
- "punishment_count": 1,
1020
- "buffer_size": 272
1021
- },
1022
- {
1023
- "step": 68,
1024
- "accuracy": 0.46484375,
1025
- "action": "apply_best_delta_and_consolidate",
1026
- "punishment_count": 0,
1027
- "buffer_size": 256
1028
- },
1029
- {
1030
- "step": 69,
1031
- "accuracy": 0.4653846153846154,
1032
- "action": "none",
1033
- "punishment_count": 0,
1034
- "buffer_size": 260
1035
- }
1036
- ],
1037
- "final_v2_metrics": {
1038
- "version": "V2-dynamic",
1039
- "n_hypotheses": 8,
1040
- "n_hypotheses_active": 8,
1041
- "max_n_hypotheses": 16,
1042
- "n_trials": 6,
1043
- "hyp_train_steps": 20,
1044
- "hyp_lr": 0.0001,
1045
- "delta_scale": 0.0010000000474974513,
1046
- "n_generators": 16,
1047
- "punishment_count": 0,
1048
- "success_count": 0,
1049
- "training_ready": false,
1050
- "classifier_trained": true,
1051
- "ewc_reference_set": true,
1052
- "buffer_size": 256,
1053
- "dynamic_adaptation": {
1054
- "loss_history_len": 8,
1055
- "loss_stats": {
1056
- "slope": NaN,
1057
- "volatility": NaN,
1058
- "mean": NaN,
1059
- "std": NaN,
1060
- "n": 8
1061
- },
1062
- "punishment_rate": 1.0,
1063
- "punishment_window_size": 12,
1064
- "n_adaptations": 60,
1065
- "limits": {
1066
- "min_n_hypotheses": 4,
1067
- "max_n_hypotheses": 16,
1068
- "min_n_trials": 1,
1069
- "max_n_trials": 6,
1070
- "min_hyp_train_steps": 5,
1071
- "max_hyp_train_steps": 60
1072
- },
1073
- "last_5_adaptations": [
1074
- {
1075
- "trigger": "punishment",
1076
- "step": 55,
1077
- "before": {
1078
- "n_hypotheses": 8,
1079
- "n_trials": 6,
1080
- "hyp_train_steps": 20
1081
- },
1082
- "after": {
1083
- "n_hypotheses": 8,
1084
- "n_trials": 6,
1085
- "hyp_train_steps": 20
1086
- },
1087
- "adapted": false,
1088
- "rules_fired": [],
1089
- "loss_stats": {
1090
- "slope": NaN,
1091
- "volatility": NaN,
1092
- "mean": NaN,
1093
- "std": NaN,
1094
- "n": 8
1095
- },
1096
- "punishment_rate": 1.0
1097
- },
1098
- {
1099
- "trigger": "auto",
1100
- "step": 56,
1101
- "before": {
1102
- "n_hypotheses": 8,
1103
- "n_trials": 6,
1104
- "hyp_train_steps": 20
1105
- },
1106
- "after": {
1107
- "n_hypotheses": 8,
1108
- "n_trials": 6,
1109
- "hyp_train_steps": 20
1110
- },
1111
- "adapted": false,
1112
- "rules_fired": [],
1113
- "loss_stats": {
1114
- "slope": NaN,
1115
- "volatility": NaN,
1116
- "mean": NaN,
1117
- "std": NaN,
1118
- "n": 8
1119
- },
1120
- "punishment_rate": 1.0
1121
- },
1122
- {
1123
- "trigger": "punishment",
1124
- "step": 57,
1125
- "before": {
1126
- "n_hypotheses": 8,
1127
- "n_trials": 6,
1128
- "hyp_train_steps": 20
1129
- },
1130
- "after": {
1131
- "n_hypotheses": 8,
1132
- "n_trials": 6,
1133
- "hyp_train_steps": 20
1134
- },
1135
- "adapted": false,
1136
- "rules_fired": [],
1137
- "loss_stats": {
1138
- "slope": NaN,
1139
- "volatility": NaN,
1140
- "mean": NaN,
1141
- "std": NaN,
1142
- "n": 8
1143
- },
1144
- "punishment_rate": 1.0
1145
- },
1146
- {
1147
- "trigger": "auto",
1148
- "step": 58,
1149
- "before": {
1150
- "n_hypotheses": 8,
1151
- "n_trials": 6,
1152
- "hyp_train_steps": 20
1153
- },
1154
- "after": {
1155
- "n_hypotheses": 8,
1156
- "n_trials": 6,
1157
- "hyp_train_steps": 20
1158
- },
1159
- "adapted": false,
1160
- "rules_fired": [],
1161
- "loss_stats": {
1162
- "slope": NaN,
1163
- "volatility": NaN,
1164
- "mean": NaN,
1165
- "std": NaN,
1166
- "n": 8
1167
- },
1168
- "punishment_rate": 1.0
1169
- },
1170
- {
1171
- "trigger": "punishment",
1172
- "step": 59,
1173
- "before": {
1174
- "n_hypotheses": 8,
1175
- "n_trials": 6,
1176
- "hyp_train_steps": 20
1177
- },
1178
- "after": {
1179
- "n_hypotheses": 8,
1180
- "n_trials": 6,
1181
- "hyp_train_steps": 20
1182
- },
1183
- "adapted": false,
1184
- "rules_fired": [],
1185
- "loss_stats": {
1186
- "slope": NaN,
1187
- "volatility": NaN,
1188
- "mean": NaN,
1189
- "std": NaN,
1190
- "n": 8
1191
- },
1192
- "punishment_rate": 1.0
1193
- }
1194
- ]
1195
- }
1196
- },
1197
- "n_adaptations": 60,
1198
- "mem_critical_stopped": false
1199
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v6_5_v2_report.json DELETED
@@ -1,177 +0,0 @@
1
- {
2
- "version": "V6.5-V2",
3
- "timestamp": "2026-08-09T03:50:50.214658",
4
- "config": {
5
- "som_grid": [
6
- 6,
7
- 6,
8
- 6,
9
- 4
10
- ],
11
- "n_neurons": 864,
12
- "hidden_dim": 1024,
13
- "vocab_size": 16384,
14
- "n_hypotheses": 16,
15
- "n_trials": 3,
16
- "hyp_train_steps": 30,
17
- "stream_batch_size": 100,
18
- "meta_conhecimento": 8000,
19
- "meta_punicão": 2000,
20
- "conhecimento_datasets": [
21
- "dominguesm/restore-punctuation-ptbr-dataset",
22
- "carolina-c4ai/corpus-carolina",
23
- "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
24
- "dominguesm/Canarim-Instruct-PTBR-Dataset",
25
- "adalbertojunior/punctuation-ptbr",
26
- "iara-project/news-articles-ptbr-dataset",
27
- "manoela/noticias_ptbr",
28
- "BrunoN-Dev/corpus-ptbr-v1"
29
- ],
30
- "punicão_dataset": "BrunoN-Dev/corpus-ptbr-v1"
31
- },
32
- "xeon_status": {
33
- "version": "V6",
34
- "physical_cores": 2,
35
- "env": {
36
- "MKL_ENABLE_INSTRUCTIONS": "AVX512",
37
- "MKL_NUM_THREADS": "2",
38
- "OMP_NUM_THREADS": "2",
39
- "MKL_DYNAMIC": "FALSE",
40
- "DNNL_PRIMITIVE_CACHE_CAPACITY": "1024",
41
- "ONEDNN_MAX_CPU_ISA": "AMX_INT8",
42
- "KMP_AFFINITY": "granularity=fine,compact,1,0",
43
- "KMP_BLOCKTIME": "1"
44
- },
45
- "avx512": {
46
- "supported": true,
47
- "desc": "AVX512_VNNI (full INT8 acceleration)"
48
- },
49
- "amx": {
50
- "supported": true,
51
- "desc": "AMX (tile + int8 + bf16) — full AMX acceleration"
52
- },
53
- "ipex_available": false,
54
- "init_done": true
55
- },
56
- "fp16_benchmark": {
57
- "best_time_ms": 93.99212000062107,
58
- "avg_time_ms": 98.73566050009686,
59
- "best_tflops": 1.361816288420287,
60
- "avg_tflops": 1.2963907807136654,
61
- "matrix_size": 4000.0
62
- },
63
- "v2_verification": {
64
- "checks": {
65
- "v2_instantiation": {
66
- "status": "PASS",
67
- "details": "n_hyp=4/8 (active=4), n_trials=2, delta_scale=0.0100"
68
- },
69
- "predict_dynamic_labels": {
70
- "status": "PASS",
71
- "details": "predict returned: negative_class (dynamic, not hardcoded)"
72
- },
73
- "process_batch_v2_conhecimento": {
74
- "status": "PASS",
75
- "details": "phase=CONHECIMENTO, action=none"
76
- },
77
- "v2_methods_exist": {
78
- "status": "PASS",
79
- "details": "train_hypotheses, select_best_delta, apply_best_delta_and_consolidate, process_batch_v2, get_v2_metrics"
80
- }
81
- },
82
- "n_pass": 4,
83
- "n_fail": 0,
84
- "all_pass": true
85
- },
86
- "fase_1_conhecimento_summary": {
87
- "total_samples": 500,
88
- "meta_atingida": false,
89
- "elapsed_s": 37.09058332443237,
90
- "storage_critical_stopped": true
91
- },
92
- "fase_2_punicão_summary": {
93
- "total_samples": 0,
94
- "meta_atingida": false,
95
- "elapsed_s": 0.0,
96
- "punishment_events": 0,
97
- "hypotheses_trainings": 0,
98
- "delta_applications": 0,
99
- "skipped": true
100
- },
101
- "attention_eval_summary": {
102
- "active": true,
103
- "logic_functional": true,
104
- "n_calls": 500,
105
- "assessment": "PASS"
106
- },
107
- "predict_fix_summary": {
108
- "n_returns_gato": 0,
109
- "n_returns_cachorro": 0,
110
- "n_returns_registry_label": 6,
111
- "n_returns_default_label": 0,
112
- "hardcoded_bug_present": false,
113
- "predict_fix_verified": true
114
- },
115
- "user_questions_summary": {
116
- "n_with_answer": 3,
117
- "n_with_think": 0,
118
- "answer_rate": 1.0,
119
- "think_rate": 0.0,
120
- "avg_latency_ms": 4.463593165079753,
121
- "avg_reasoning_length": 69.0
122
- },
123
- "model_states_saved_to": "/home/z/my-project/BiGRU_T_version/v6_5_v2_model_states.pt",
124
- "save_info": {
125
- "saved": true,
126
- "path": "/home/z/my-project/BiGRU_T_version/v6_5_v2_model_states.pt",
127
- "size_mb": 217.669998,
128
- "size_gb": 0.20272098295390606,
129
- "size_status": "OK",
130
- "size_within_1gb_limit": true,
131
- "reason": "end_of_training_v2",
132
- "step": 35,
133
- "total_samples": 500,
134
- "n_tensors": 7,
135
- "n_buffer_tail": 64
136
- },
137
- "final_v2_metrics": {
138
- "version": "V2-dynamic",
139
- "n_hypotheses": 16,
140
- "n_hypotheses_active": 16,
141
- "max_n_hypotheses": 32,
142
- "n_trials": 3,
143
- "hyp_train_steps": 30,
144
- "hyp_lr": 0.0001,
145
- "delta_scale": 0.009999999776482582,
146
- "n_generators": 32,
147
- "punishment_count": 0,
148
- "success_count": 0,
149
- "training_ready": true,
150
- "classifier_trained": false,
151
- "ewc_reference_set": false,
152
- "buffer_size": 128,
153
- "total_hyp_steps_executed": 0,
154
- "n_train_hyp_calls": 0,
155
- "dynamic_adaptation": {
156
- "loss_history_len": 0,
157
- "loss_stats": {
158
- "slope": 0.0,
159
- "volatility": 0.0,
160
- "mean": 0.0,
161
- "n": 0
162
- },
163
- "punishment_rate": 0.0,
164
- "punishment_window_size": 0,
165
- "n_adaptations": 0,
166
- "limits": {
167
- "min_n_hypotheses": 4,
168
- "max_n_hypotheses": 32,
169
- "min_n_trials": 1,
170
- "max_n_trials": 6,
171
- "min_hyp_train_steps": 10,
172
- "max_hyp_train_steps": 80
173
- },
174
- "last_5_adaptations": []
175
- }
176
- }
177
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v6_5_v2_user_questions.json DELETED
@@ -1,82 +0,0 @@
1
- {
2
- "evaluation": "user_questions_without_help_v65_v2",
3
- "user_requirement": "não ajudar o modelo em respostas e lançar perguntas",
4
- "questions_sent_verbatim": true,
5
- "no_context_added": true,
6
- "no_system_prompt": true,
7
- "no_few_shot": true,
8
- "n_questions": 3,
9
- "questions": [
10
- "Luva de Pedreiro Távila",
11
- "Lula reserva valor",
12
- "Amazonas força-tarefa vítimas"
13
- ],
14
- "results": [
15
- {
16
- "query": "Luva de Pedreiro Távila",
17
- "query_was_modified": false,
18
- "context_provided": false,
19
- "system_prompt_used": false,
20
- "few_shot_examples": false,
21
- "som_prediction": "punctuated",
22
- "reasoning_length": 69,
23
- "has_think": false,
24
- "has_plan": false,
25
- "has_answer": true,
26
- "has_decompose": false,
27
- "think_preview": "",
28
- "answer_preview": "ReasoningEngine disabled. SOM prediction: punctuated",
29
- "raw_response_preview": "<answer>ReasoningEngine disabled. SOM prediction: punctuated</answer>",
30
- "n_tags": 1,
31
- "latency_ms": 4.607677459716797
32
- },
33
- {
34
- "query": "Lula reserva valor",
35
- "query_was_modified": false,
36
- "context_provided": false,
37
- "system_prompt_used": false,
38
- "few_shot_examples": false,
39
- "som_prediction": "punctuated",
40
- "reasoning_length": 69,
41
- "has_think": false,
42
- "has_plan": false,
43
- "has_answer": true,
44
- "has_decompose": false,
45
- "think_preview": "",
46
- "answer_preview": "ReasoningEngine disabled. SOM prediction: punctuated",
47
- "raw_response_preview": "<answer>ReasoningEngine disabled. SOM prediction: punctuated</answer>",
48
- "n_tags": 1,
49
- "latency_ms": 4.328012466430664
50
- },
51
- {
52
- "query": "Amazonas força-tarefa vítimas",
53
- "query_was_modified": false,
54
- "context_provided": false,
55
- "system_prompt_used": false,
56
- "few_shot_examples": false,
57
- "som_prediction": "punctuated",
58
- "reasoning_length": 69,
59
- "has_think": false,
60
- "has_plan": false,
61
- "has_answer": true,
62
- "has_decompose": false,
63
- "think_preview": "",
64
- "answer_preview": "ReasoningEngine disabled. SOM prediction: punctuated",
65
- "raw_response_preview": "<answer>ReasoningEngine disabled. SOM prediction: punctuated</answer>",
66
- "n_tags": 1,
67
- "latency_ms": 4.455089569091797
68
- }
69
- ],
70
- "summary": {
71
- "n_with_answer": 3,
72
- "n_with_think": 0,
73
- "answer_rate": 1.0,
74
- "think_rate": 0.0,
75
- "avg_latency_ms": 4.463593165079753,
76
- "avg_reasoning_length": 69.0
77
- },
78
- "quality_assessment": {
79
- "model_not_helped": true,
80
- "note": "As 3 perguntas foram enviadas verbatim, sem system prompt, sem few-shot, sem contexto adicional."
81
- }
82
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vqvae2_hierarchical.py DELETED
@@ -1,200 +0,0 @@
1
- """
2
- Xavante - vqvae2_hierarchical.py
3
- Responsabilidade: VQ-VAE-2 hierarquica (Teorema 13.1/13.2/13.3).
4
- Reutiliza implementacao validada do FlexNet com EMA + Goose VQ + dead code restart.
5
- Referencia: Razavi et al. 2019 - Generating Diverse High-Fidelity Images with VQ-VAE-2.
6
- """
7
- from __future__ import annotations
8
-
9
- import logging
10
- import math
11
- from typing import List, Tuple
12
-
13
- import torch
14
- import torch.nn as nn
15
- import torch.nn.functional as F
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- class VectorQuantizerEMA(nn.Module):
21
- """
22
- VQ com atualizacao EMA do codebook (validado no FlexNet).
23
- Inclui: dead code restart, commitment loss, Goose VQ.
24
- v6 aprimoramentos:
25
- - Diversity loss (entropy bonus) para forcar uso uniforme do codebook
26
- - Commitment warmup: beta_t = beta_0 * min(1, t/warmup)
27
- - EMA restart mais agressivo (decay adaptativo)
28
- """
29
-
30
- def __init__(
31
- self,
32
- num_embeddings: int,
33
- embedding_dim: int,
34
- commitment_cost: float = 0.25,
35
- decay: float = 0.99,
36
- epsilon: float = 1e-5,
37
- dead_threshold: int = 1,
38
- diversity_weight: float = 0.1,
39
- warmup_steps: int = 500,
40
- ):
41
- super().__init__()
42
- self.num_embeddings = num_embeddings
43
- self.embedding_dim = embedding_dim
44
- self.commitment_cost = commitment_cost
45
- self.decay = decay
46
- self.epsilon = epsilon
47
- self.dead_threshold = dead_threshold
48
- self.diversity_weight = diversity_weight
49
- self.warmup_steps = warmup_steps
50
- self._step = 0
51
-
52
- embed = torch.empty(num_embeddings, embedding_dim)
53
- nn.init.normal_(embed, mean=0.0, std=0.02)
54
- self.register_buffer("embeddings", embed)
55
- self.register_buffer("ema_count", torch.zeros(num_embeddings))
56
- self.register_buffer("ema_weight", embed.clone())
57
- self.register_buffer("usage_count", torch.zeros(num_embeddings, dtype=torch.long))
58
-
59
- def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
60
- """
61
- x: [B, D, H, W] ou [B, D]
62
- Retorna (quantized, loss, encoding_indices)
63
- """
64
- if x.dim() == 4:
65
- # [B, D, H, W] -> [B, H, W, D] -> [B*H*W, D]
66
- B, D, H, W = x.shape
67
- flat = x.permute(0, 2, 3, 1).reshape(-1, self.embedding_dim)
68
- else:
69
- # [B, D] -> [B, D]
70
- flat = x.reshape(-1, self.embedding_dim)
71
- # Distancia
72
- distances = (
73
- flat.pow(2).sum(1, keepdim=True)
74
- - 2 * flat @ self.embeddings.t()
75
- + self.embeddings.pow(2).sum(1)
76
- )
77
- indices = torch.argmin(distances, dim=1)
78
- one_hot = F.one_hot(indices, self.num_embeddings).type(flat.dtype)
79
- quantized = one_hot @ self.embeddings
80
- # Uso
81
- self.usage_count.index_add_(0, indices, torch.ones_like(indices))
82
-
83
- # EMA update
84
- if self.training:
85
- with torch.no_grad():
86
- count = one_hot.sum(0)
87
- ema_count_new = self.decay * self.ema_count + (1 - self.decay) * count
88
- total = ema_count_new.sum()
89
- ema_count_new = (ema_count_new + self.epsilon) / (total + self.num_embeddings * self.epsilon) * total
90
- dw = one_hot.t() @ flat
91
- self.ema_weight = self.decay * self.ema_weight + (1 - self.decay) * dw
92
- self.ema_count = ema_count_new
93
- self.embeddings.copy_(self.ema_weight / self.ema_count.unsqueeze(1))
94
-
95
- # Dead code restart
96
- dead = self.usage_count < self.dead_threshold
97
- if dead.any() and flat.shape[0] > 0:
98
- dead_indices = dead.nonzero(as_tuple=True)[0]
99
- n_dead = dead_indices.shape[0]
100
- # Sample min(n_dead, flat.shape[0]) candidates from flat
101
- n_replace = min(n_dead, flat.shape[0])
102
- if n_replace > 0:
103
- idx = torch.randperm(flat.shape[0])[:n_replace].to(flat.device)
104
- # Substituir apenas n_replace codigos mortos
105
- self.embeddings.data[dead_indices[:n_replace]] = flat[idx].detach()
106
-
107
- # Commitment loss com warmup
108
- self._step += 1
109
- beta = self.commitment_cost * min(1.0, self._step / max(self.warmup_steps, 1))
110
- e_latent_loss = F.mse_loss(quantized.detach(), flat)
111
- q_latent_loss = F.mse_loss(quantized, flat.detach())
112
- # Diversity loss: -H(p) onde p = freq de uso de cada code
113
- # Maximizar entropia = forçar uso uniforme do codebook
114
- if self.diversity_weight > 0 and self.training:
115
- code_probs = one_hot.float().mean(dim=0) # [num_embeddings]
116
- code_probs = code_probs.clamp_min(1e-10)
117
- entropy = -(code_probs * code_probs.log()).sum()
118
- diversity_loss = -entropy / math.log(self.num_embeddings) # normalize to [0, 1]
119
- else:
120
- diversity_loss = torch.tensor(0.0, device=x.device)
121
- loss = q_latent_loss + beta * e_latent_loss + self.diversity_weight * diversity_loss
122
-
123
- # Straight-through
124
- quantized = flat + (quantized - flat).detach()
125
- # Restore shape
126
- if x.dim() == 4:
127
- quantized = quantized.view(B, H, W, D).permute(0, 3, 1, 2).contiguous()
128
- indices = indices.view(B, H, W)
129
- else:
130
- quantized = quantized.view_as(x)
131
- return quantized, loss, indices
132
-
133
-
134
- class HierarchicalVQVAE2(nn.Module):
135
- """
136
- VQ-VAE-2 com 2 niveis: top (global) e bottom (local).
137
- Mapeia: Teorema 13.1/13.2/13.3.
138
- """
139
-
140
- def __init__(
141
- self,
142
- in_channels: int = 3,
143
- hidden_dim: int = 64,
144
- top_codebook: int = 128,
145
- bottom_codebook: int = 512,
146
- commitment_cost: float = 0.25,
147
- decay: float = 0.99,
148
- ):
149
- super().__init__()
150
- self.encoder_bottom = nn.Sequential(
151
- nn.Conv2d(in_channels, hidden_dim, 4, 2, 1),
152
- nn.GELU(),
153
- nn.Conv2d(hidden_dim, hidden_dim, 4, 2, 1),
154
- nn.GELU(),
155
- nn.Conv2d(hidden_dim, hidden_dim, 3, 1, 1),
156
- )
157
- self.encoder_top = nn.Sequential(
158
- nn.Conv2d(hidden_dim, hidden_dim, 4, 2, 1),
159
- nn.GELU(),
160
- nn.Conv2d(hidden_dim, hidden_dim, 4, 2, 1),
161
- nn.GELU(),
162
- nn.Conv2d(hidden_dim, hidden_dim, 3, 1, 1),
163
- )
164
- self.vq_top = VectorQuantizerEMA(top_codebook, hidden_dim, commitment_cost, decay)
165
- self.vq_bottom = VectorQuantizerEMA(bottom_codebook, hidden_dim, commitment_cost, decay)
166
- self.decoder_top = nn.Sequential(
167
- nn.ConvTranspose2d(hidden_dim, hidden_dim, 4, 2, 1),
168
- nn.GELU(),
169
- nn.ConvTranspose2d(hidden_dim, hidden_dim, 4, 2, 1),
170
- nn.GELU(),
171
- )
172
- self.decoder_bottom = nn.Sequential(
173
- nn.ConvTranspose2d(hidden_dim * 2, hidden_dim, 4, 2, 1),
174
- nn.GELU(),
175
- nn.ConvTranspose2d(hidden_dim, hidden_dim, 4, 2, 1),
176
- nn.GELU(),
177
- nn.Conv2d(hidden_dim, in_channels, 3, 1, 1),
178
- )
179
-
180
- def forward(self, x: torch.Tensor) -> dict:
181
- # Bottom encode
182
- ze_b = self.encoder_bottom(x)
183
- # Top encode
184
- ze_t = self.encoder_top(ze_b)
185
- zq_t, loss_t, idx_t = self.vq_top(ze_t)
186
- # Decodifica top e soma com bottom
187
- dec_t = self.decoder_top(zq_t)
188
- # Concat com bottom quantized
189
- zq_b, loss_b, idx_b = self.vq_bottom(ze_b)
190
- cat = torch.cat([dec_t, zq_b], dim=1)
191
- x_recon = self.decoder_bottom(cat)
192
- return {
193
- "reconstruction": x_recon,
194
- "loss": loss_t + loss_b,
195
- "top_indices": idx_t,
196
- "bottom_indices": idx_b,
197
- }
198
-
199
-
200
- __all__ = ["VectorQuantizerEMA", "HierarchicalVQVAE2"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vqvae2_hierarchical_flexnet.py DELETED
@@ -1,513 +0,0 @@
1
- """
2
- vqvae2_hierarchical — VQ-VAE-2 (Razavi 2019) hierárquico com 2 níveis de codebook.
3
-
4
- Arquitetura:
5
- - Top level: codebook K_top captura estrutura global (low-resolution)
6
- - Bottom level: codebook K_bot captura detalhes locais (high-resolution)
7
- - Cada nível tem encoder/decoder proprio
8
- - Residual quantization: bottom level quantiza o RESÍDUO do top level
9
-
10
- Loss total:
11
- L = ||x - D(top_q, bot_q)||²
12
- + ||sg[z_top] - top_q||² + β·||z_top - sg[top_q]||²
13
- + ||sg[z_bot] - bot_q||² + β·||z_bot - sg[bot_q]||²
14
-
15
- Implementa:
16
- - EMA updates em ambos codebooks
17
- - Dead code restart em ambos codebooks
18
- - Goose VQ com schedule de temperatura (alto→baixo)
19
-
20
- Setup dos testes (solicitado):
21
- - batch=256, K_top=512, K_bot=512
22
- - Goose τ schedule: começa 2.0, decai para 0.5 via cosine
23
- - EMA decay γ=0.99
24
- - Dead code restart a cada 3 épocas
25
- """
26
-
27
- from __future__ import annotations
28
- from typing import Dict, Optional, Tuple
29
-
30
- import math
31
- import numpy as np
32
- import torch
33
- import torch.nn as nn
34
- import torch.nn.functional as F
35
-
36
-
37
- # ============================================================
38
- # v12.8: Normalizações alternativas (substituem LayerNorm v12.7)
39
- # ============================================================
40
-
41
- class RMSNorm(nn.Module):
42
- """RMSNorm — preserva magnitude (não subtrai média como LayerNorm).
43
-
44
- y = x / sqrt(mean(x²) + eps) * gamma
45
-
46
- Vantagens sobre LayerNorm:
47
- - Mais barato (sem cálculo de variância)
48
- - Preserva magnitude do sinal (importante para VQ-VAE)
49
- - Zhang & Sennrich 2019
50
- """
51
-
52
- def __init__(self, dim: int, eps: float = 1e-6):
53
- super().__init__()
54
- self.gamma = nn.Parameter(torch.ones(dim))
55
- self.eps = eps
56
-
57
- def forward(self, x: torch.Tensor) -> torch.Tensor:
58
- rms = torch.sqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
59
- return self.gamma * x / rms
60
-
61
-
62
- def apply_weightnorm(module: nn.Module) -> nn.Module:
63
- """Aplica weight normalization (EnCodec-style) a um módulo Linear.
64
-
65
- Salakhutdinov & Wang 2016: w = g * v / ||v||, onde g é escalar aprendido.
66
-
67
- Vantagens:
68
- - Normaliza apenas o peso, não a ativação
69
- - Preserva estatística do input (importante para VQ-VAE)
70
- - Usado em EnCodec (Défossez 2022) e SoundStream (Zeghidour 2021)
71
- """
72
- return nn.utils.weight_norm(module)
73
-
74
-
75
- class HierarchicalVectorQuantizer(nn.Module):
76
- """Quantizador hierárquico com 2 níveis (top + bottom) e técnicas anti-collapse.
77
-
78
- Args:
79
- num_codes_top: K_top (codebook de topo, captura estrutura global)
80
- num_codes_bot: K_bot (codebook de base, captura detalhes)
81
- code_dim: D (dimensão compartilhada)
82
- beta: peso do commitment loss
83
- ema_decay: γ para EMA (default 0.99)
84
- dead_code_threshold: N_k abaixo do qual código é morto
85
- dead_code_restart_every: a cada quantas épocas verificar
86
- goose_temp_init: temperatura Goose inicial (default 2.0)
87
- goose_temp_final: temperatura Goose final (default 0.5)
88
- goose_schedule: 'cosine' ou 'linear'
89
- total_epochs: total de épocas (para schedule)
90
- """
91
-
92
- def __init__(
93
- self,
94
- num_codes_top: int = 512,
95
- num_codes_bot: int = 512,
96
- code_dim: int = 32,
97
- beta: float = 0.25,
98
- ema_decay: float = 0.99,
99
- dead_code_threshold: float = 1.0,
100
- dead_code_restart_every: int = 3,
101
- goose_temp_init: float = 2.0,
102
- goose_temp_final: float = 0.5,
103
- goose_schedule: str = "cosine",
104
- total_epochs: int = 25,
105
- norm_type: str = "none", # v12.8: "none" | "weightnorm" | "rmsnorm"
106
- ):
107
- super().__init__()
108
- self.num_codes_top = num_codes_top
109
- self.num_codes_bot = num_codes_bot
110
- self.code_dim = code_dim
111
- self.beta = beta
112
- self.ema_decay = ema_decay
113
- self.dead_code_threshold = dead_code_threshold
114
- self.dead_code_restart_every = dead_code_restart_every
115
- self.goose_temp_init = goose_temp_init
116
- self.goose_temp_final = goose_temp_final
117
- self.goose_schedule = goose_schedule
118
- self.total_epochs = total_epochs
119
- self.norm_type = norm_type # v12.8
120
-
121
- # Codebooks (buffers, atualizados via EMA).
122
- self.register_buffer('codebook_top', torch.randn(num_codes_top, code_dim) * 0.05)
123
- self.register_buffer('codebook_bot', torch.randn(num_codes_bot, code_dim) * 0.05)
124
- # EMA state para top.
125
- self.register_buffer('ema_cluster_top', torch.zeros(num_codes_top))
126
- self.register_buffer('ema_w_top', torch.zeros(num_codes_top, code_dim))
127
- # EMA state para bottom.
128
- self.register_buffer('ema_cluster_bot', torch.zeros(num_codes_bot))
129
- self.register_buffer('ema_w_bot', torch.zeros(num_codes_bot, code_dim))
130
-
131
- # v12.8: Normalização opcional dentro do VQ (substitui LayerNorm v12.7 que degradou).
132
- # - "none": sem normalização (preserva estatística original — RECOMENDADO para VQ-VAE)
133
- # - "weightnorm": weight normalization (EnCodec-style, preserva magnitude)
134
- # - "rmsnorm": RMSNorm (preserva magnitude, mais barato que LayerNorm)
135
- # Nota: LayerNorm v12.7 foi REMOVIDO pois degradou resultados (17× pior loss).
136
- if norm_type == "rmsnorm":
137
- # RMSNorm: y = x / sqrt(mean(x²) + eps) * gamma
138
- self.rms_pre_top = RMSNorm(code_dim)
139
- self.rms_pre_bot = RMSNorm(code_dim)
140
- self.rms_post_combine = RMSNorm(code_dim)
141
- else:
142
- # "none" ou "weightnorm" (weightnorm é aplicado nos encoders, não aqui).
143
- self.rms_pre_top = nn.Identity()
144
- self.rms_pre_bot = nn.Identity()
145
- self.rms_post_combine = nn.Identity()
146
-
147
- # Contador de épocas.
148
- self.register_buffer('epoch_counter', torch.zeros(1, dtype=torch.long))
149
-
150
- # Estatísticas de uso.
151
- self.register_buffer('usage_top', torch.zeros(num_codes_top))
152
- self.register_buffer('usage_bot', torch.zeros(num_codes_bot))
153
-
154
- # Temperatura Goose atual (atualizada via update_temperature).
155
- self.register_buffer('current_temp', torch.tensor(goose_temp_init))
156
-
157
- def update_temperature(self, grad_recon: float = None, grad_vq: float = None):
158
- """Atualiza temperatura Goose baseada na época atual (schedule).
159
-
160
- v13.9: Se grad_recon e grad_vq fornecidos, usa mas_weight adaptativo:
161
- τ* = ||∇L_recon|| / ||∇L_vq||
162
- Caso contrário, usa cosine decay padrão.
163
- """
164
- epoch = int(self.epoch_counter.item())
165
- progress = min(epoch / max(self.total_epochs, 1), 1.0)
166
-
167
- if grad_recon is not None and grad_vq is not None and grad_vq > 1e-8:
168
- # v13.9: τ* adaptativo via mas_weight formula.
169
- from .mathematical_optimizations import compute_goose_tau_adaptive
170
- prev_tau = float(self.current_temp)
171
- temp = compute_goose_tau_adaptive(grad_recon, grad_vq, prev_tau,
172
- tau_min=self.goose_temp_final,
173
- tau_max=self.goose_temp_init)
174
- elif self.goose_schedule == "cosine":
175
- temp = self.goose_temp_final + 0.5 * (self.goose_temp_init - self.goose_temp_final) * \
176
- (1 + math.cos(math.pi * progress))
177
- else: # linear
178
- temp = self.goose_temp_init + (self.goose_temp_final - self.goose_temp_init) * progress
179
- self.current_temp.fill_(temp)
180
- return float(temp)
181
-
182
- def _quantize_level(self, z: torch.Tensor, codebook: torch.Tensor,
183
- ema_cluster: torch.Tensor, ema_w: torch.Tensor,
184
- use_goose: bool = True) -> Tuple[torch.Tensor, torch.Tensor, int]:
185
- """Quantiza um nível (top ou bottom) com EMA + Goose opcional."""
186
- B, D = z.shape
187
- # Distâncias.
188
- dist = (
189
- z.pow(2).sum(dim=1, keepdim=True)
190
- + codebook.pow(2).sum(dim=1)
191
- - 2 * z @ codebook.t()
192
- ) # (B, K)
193
-
194
- if use_goose and self.training:
195
- # Goose VQ: Gumbel-softmax sampling.
196
- logits = -dist / max(float(self.current_temp), 1e-6)
197
- codes_soft = F.gumbel_softmax(logits, tau=float(self.current_temp), hard=True)
198
- codes = codes_soft.argmax(dim=1)
199
- z_q = codes_soft @ codebook
200
- else:
201
- # argmin (eval ou fallback).
202
- codes = dist.argmin(dim=1)
203
- z_q = codebook[codes]
204
-
205
- # EMA update (apenas em treino).
206
- n_restarted = 0
207
- if self.training:
208
- one_hot = F.one_hot(codes, codebook.size(0)).float()
209
- new_cluster = one_hot.sum(dim=0)
210
- # v13.3fix: Save OLD values before EMA update for cb_update computation
211
- old_cluster = ema_cluster.clone()
212
- old_w = ema_w.clone()
213
- ema_cluster.mul_(self.ema_decay).add_(new_cluster, alpha=1 - self.ema_decay)
214
- new_w = one_hot.t() @ z
215
- ema_w.mul_(self.ema_decay).add_(new_w, alpha=1 - self.ema_decay)
216
- # v13.3: Correções matemáticas no EMA (mal-conditioning do codebook).
217
- # Use OLD (pre-update) values for cb_update, as required by proper EMA formula.
218
- n_old = old_cluster.sum()
219
- # 1. Smoothing do cluster size (reduz condition number).
220
- cluster_mean = old_cluster.mean()
221
- cluster_smoothed = 0.9 * old_cluster + 0.1 * cluster_mean
222
- # 2. Clipping logarítmico do cluster size (comprime escala dinâmica).
223
- eps_cb = 1e-5
224
- cluster_clipped = torch.log1p(cluster_smoothed / eps_cb) / \
225
- torch.log1p(cluster_smoothed.max() / eps_cb + 1e-12)
226
- # 3. Renormalizar para magnitude original.
227
- cluster_final = cluster_clipped * n_old / (cluster_clipped.sum() + 1e-12)
228
- smoothed = (cluster_final + eps_cb) / (n_old + codebook.size(0) * eps_cb) * n_old
229
- # v13.3: Clamp do codebook update para prevenir NaN/Inf.
230
- # Use OLD ema_w (pre-update) for cb_update
231
- cb_update = old_w / smoothed.unsqueeze(1)
232
- cb_update = torch.clamp(cb_update, -1e4, 1e4)
233
- codebook.copy_(cb_update)
234
-
235
- # Dead code restart.
236
- if (int(self.epoch_counter.item()) + 1) % self.dead_code_restart_every == 0:
237
- dead_mask = ema_cluster < self.dead_code_threshold
238
- n_dead = int(dead_mask.sum().item())
239
- if n_dead > 0:
240
- rand_idx = torch.randint(0, B, (n_dead,), device=z.device)
241
- replacement = z[rand_idx]
242
- codebook.data[dead_mask] = replacement.detach()
243
- ema_cluster[dead_mask] = 1.0
244
- ema_w[dead_mask] = replacement.detach()
245
- n_restarted = n_dead
246
- # v13.1: limpeza leve após dead code restart (libera tensores temporários).
247
- import gc as _gc
248
- _gc.collect(0)
249
-
250
- return z_q, codes, n_restarted
251
-
252
- def forward(self, z_e: torch.Tensor) -> Dict[str, torch.Tensor]:
253
- """
254
- z_e: (B, D) — saída contínua do encoder.
255
-
256
- Retorna dict com:
257
- z_q_top: (B, D) — vetores quantizados do nível top
258
- z_q_bot: (B, D) — vetores quantizados do nível bottom (residual)
259
- z_q_combined: (B, D) — z_q_top + z_q_bot (soma)
260
- codes_top: (B,)
261
- codes_bot: (B,)
262
- loss: escalar (commitment top + bottom)
263
- stats: dict com estatísticas
264
- """
265
- # v12.8: RMSNorm pré-top (preserva magnitude, mais estável que LayerNorm).
266
- z_e_norm = self.rms_pre_top(z_e)
267
-
268
- # Nível top: quantiza z_e (normalizado) diretamente.
269
- z_q_top, codes_top, n_restart_top = self._quantize_level(
270
- z_e_norm, self.codebook_top, self.ema_cluster_top, self.ema_w_top,
271
- use_goose=True,
272
- )
273
-
274
- # Nível bottom: quantiza o RESÍDUO z_e - z_q_top.detach() (com RMSNorm).
275
- residual = z_e - z_q_top.detach()
276
- residual_norm = self.rms_pre_bot(residual)
277
- z_q_bot, codes_bot, n_restart_bot = self._quantize_level(
278
- residual_norm, self.codebook_bot, self.ema_cluster_bot, self.ema_w_bot,
279
- use_goose=True,
280
- )
281
-
282
- # Commitment losses (computadas com z_e original, não normalizado).
283
- commit_top = F.mse_loss(z_e, z_q_top.detach())
284
- commit_bot = F.mse_loss(residual, z_q_bot.detach())
285
- loss = self.beta * (commit_top + commit_bot)
286
-
287
- # Straight-through.
288
- z_q_top_st = z_e + (z_q_top - z_e).detach()
289
- z_q_bot_st = residual + (z_q_bot - residual).detach()
290
- z_q_combined = z_q_top_st + z_q_bot_st
291
- # v12.8: RMSNorm pós-combinação (preserva magnitude, mais estável que LayerNorm).
292
- z_q_combined = self.rms_post_combine(z_q_combined)
293
-
294
- # Estatísticas.
295
- with torch.no_grad():
296
- self.usage_top.add_(torch.bincount(codes_top, minlength=self.num_codes_top).float())
297
- self.usage_bot.add_(torch.bincount(codes_bot, minlength=self.num_codes_bot).float())
298
- n_used_top = int((self.usage_top > 0).sum().item())
299
- n_used_bot = int((self.usage_bot > 0).sum().item())
300
-
301
- def _cb_ppl(codes, K):
302
- if len(codes) == 0:
303
- return 0.0
304
- from collections import Counter
305
- counter = Counter(codes.tolist())
306
- probs = np.array([c / len(codes) for c in counter.values()])
307
- entropy = -np.sum(probs * np.log(probs + 1e-12))
308
- return float(math.exp(entropy)) if entropy > 0 else 0.0
309
-
310
- cb_ppl_top = _cb_ppl(codes_top, self.num_codes_top)
311
- cb_ppl_bot = _cb_ppl(codes_bot, self.num_codes_bot)
312
-
313
- stats = {
314
- 'n_used_top': n_used_top,
315
- 'n_used_bot': n_used_bot,
316
- 'n_dead_top': self.num_codes_top - n_used_top,
317
- 'n_dead_bot': self.num_codes_bot - n_used_bot,
318
- 'usage_ratio_top': n_used_top / self.num_codes_top,
319
- 'usage_ratio_bot': n_used_bot / self.num_codes_bot,
320
- 'codebook_ppl_top': cb_ppl_top,
321
- 'codebook_ppl_bot': cb_ppl_bot,
322
- 'n_restarted_top': n_restart_top,
323
- 'n_restarted_bot': n_restart_bot,
324
- 'goose_temp': float(self.current_temp),
325
- }
326
-
327
- return {
328
- 'z_q_top': z_q_top_st,
329
- 'z_q_bot': z_q_bot_st,
330
- 'z_q_combined': z_q_combined,
331
- 'codes_top': codes_top,
332
- 'codes_bot': codes_bot,
333
- 'loss': loss,
334
- 'stats': stats,
335
- }
336
-
337
- def increment_epoch(self):
338
- self.epoch_counter += 1
339
- self.update_temperature()
340
-
341
- def reset_usage_stats(self):
342
- self.usage_top.zero_()
343
- self.usage_bot.zero_()
344
-
345
-
346
- class HierarchicalVQVAE2(nn.Module):
347
- """VQ-VAE-2 completo com encoder/decoder hierárquico para múltiplas modalidades.
348
-
349
- Arquitetura:
350
- x → [Encoder shared] → z_e
351
- → [Top VQ] → z_q_top (estrutura global)
352
- → [Bot VQ] → z_q_bot (detalhes residuais)
353
- → [Decoder shared] → x_recon
354
- """
355
-
356
- def __init__(
357
- self,
358
- modalities: Dict[str, int],
359
- code_dim: int = 32,
360
- num_codes_top: int = 512,
361
- num_codes_bot: int = 512,
362
- hidden: int = 128,
363
- beta: float = 0.25,
364
- ema_decay: float = 0.99,
365
- dead_code_threshold: float = 1.0,
366
- dead_code_restart_every: int = 3,
367
- goose_temp_init: float = 2.0,
368
- goose_temp_final: float = 0.5,
369
- goose_schedule: str = "cosine",
370
- total_epochs: int = 25,
371
- norm_type: str = "none", # v12.8: "none" | "weightnorm" | "rmsnorm"
372
- rmsnorm_in_vq: bool = False, # v12.8: RMSNorm dentro do VQ (default False)
373
- ):
374
- super().__init__()
375
- self.modality_names = list(modalities.keys())
376
- self.modality_dims = modalities
377
- self.code_dim = code_dim
378
- self.norm_type = norm_type # v12.8
379
-
380
- # v12.8: Encoders e decoders por modalidade.
381
- # - "none": LayerNorm interno dos MLPs (default, melhor validado em v12.7)
382
- # - "weightnorm": aplica weight_norm nos Linear (EnCodec-style)
383
- # - "rmsnorm": usa RMSNorm em vez de LayerNorm entre camadas MLP
384
- def make_encoder(dim, hidden, code_dim, norm_type):
385
- if norm_type == "weightnorm":
386
- layers = [
387
- nn.utils.weight_norm(nn.Linear(dim, hidden)), nn.GELU(),
388
- nn.utils.weight_norm(nn.Linear(hidden, hidden // 2)), nn.GELU(),
389
- nn.utils.weight_norm(nn.Linear(hidden // 2, code_dim)),
390
- ]
391
- elif norm_type == "rmsnorm":
392
- layers = [
393
- nn.Linear(dim, hidden), RMSNorm(hidden), nn.GELU(),
394
- nn.Linear(hidden, hidden // 2), RMSNorm(hidden // 2), nn.GELU(),
395
- nn.Linear(hidden // 2, code_dim),
396
- ]
397
- else: # "none" — usa LayerNorm interno (default, melhor validado)
398
- layers = [
399
- nn.Linear(dim, hidden), nn.LayerNorm(hidden), nn.GELU(),
400
- nn.Linear(hidden, hidden // 2), nn.LayerNorm(hidden // 2), nn.GELU(),
401
- nn.Linear(hidden // 2, code_dim),
402
- ]
403
- return nn.Sequential(*layers)
404
-
405
- def make_decoder(code_dim, hidden, dim, norm_type):
406
- if norm_type == "weightnorm":
407
- layers = [
408
- nn.utils.weight_norm(nn.Linear(code_dim, hidden // 2)), nn.GELU(),
409
- nn.utils.weight_norm(nn.Linear(hidden // 2, hidden)), nn.GELU(),
410
- nn.utils.weight_norm(nn.Linear(hidden, dim)),
411
- ]
412
- elif norm_type == "rmsnorm":
413
- layers = [
414
- nn.Linear(code_dim, hidden // 2), RMSNorm(hidden // 2), nn.GELU(),
415
- nn.Linear(hidden // 2, hidden), RMSNorm(hidden), nn.GELU(),
416
- nn.Linear(hidden, dim),
417
- ]
418
- else: # "none"
419
- layers = [
420
- nn.Linear(code_dim, hidden // 2), nn.LayerNorm(hidden // 2), nn.GELU(),
421
- nn.Linear(hidden // 2, hidden), nn.LayerNorm(hidden), nn.GELU(),
422
- nn.Linear(hidden, dim),
423
- ]
424
- return nn.Sequential(*layers)
425
-
426
- self.encoders = nn.ModuleDict({
427
- name: make_encoder(dim, hidden, code_dim, norm_type)
428
- for name, dim in modalities.items()
429
- })
430
- self.decoders = nn.ModuleDict({
431
- name: make_decoder(code_dim, hidden, dim, norm_type)
432
- for name, dim in modalities.items()
433
- })
434
-
435
- # VQ hierárquico compartilhado entre todas as modalidades.
436
- # v12.8: RMSNorm opcional dentro do VQ (substitui LayerNorm v12.7 que degradou).
437
- vq_norm_type = "rmsnorm" if (rmsnorm_in_vq and norm_type == "rmsnorm") else "none"
438
- self.vq = HierarchicalVectorQuantizer(
439
- num_codes_top=num_codes_top,
440
- num_codes_bot=num_codes_bot,
441
- code_dim=code_dim,
442
- beta=beta,
443
- ema_decay=ema_decay,
444
- dead_code_threshold=dead_code_threshold,
445
- dead_code_restart_every=dead_code_restart_every,
446
- goose_temp_init=goose_temp_init,
447
- goose_temp_final=goose_temp_final,
448
- goose_schedule=goose_schedule,
449
- total_epochs=total_epochs,
450
- norm_type=vq_norm_type,
451
- )
452
-
453
- def forward(self, batch: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]:
454
- """batch: {modality_name: (B, input_dim)}."""
455
- out = {'reconstructions': {}, 'codes_top': {}, 'codes_bot': {}, 'vq_loss': 0.0,
456
- 'recon_loss': 0.0, 'stats': {}}
457
- total_vq = 0.0
458
- total_recon = 0.0
459
- n = 0
460
- all_codes_top = []
461
- all_codes_bot = []
462
- vq_out_first_stats = None # Capture stats from first VQ forward
463
- for name, x in batch.items():
464
- if name not in self.encoders:
465
- continue
466
- # v13.3: Sanitização de NaN/Inf no input (resolve bug identificado no teste adversarial).
467
- x = torch.nan_to_num(x, nan=0.0, posinf=1e4, neginf=-1e4)
468
- # v12.8: forward limpo (sem LayerNorms extras v12.7 que degradaram resultados).
469
- # Encoder (com normalização interna configurável via norm_type).
470
- z_e = self.encoders[name](x)
471
- # v13.3: Sanitização após encoder (pode gerar NaN com inputs extremos).
472
- z_e = torch.nan_to_num(z_e, nan=0.0, posinf=1e4, neginf=-1e4)
473
- # VQ hierárquico (com RMSNorm opcional via rmsnorm_in_vq).
474
- vq_out = self.vq(z_e)
475
- # Capture stats from the first modality's VQ forward (no redundant second pass)
476
- if vq_out_first_stats is None:
477
- vq_out_first_stats = vq_out['stats']
478
- z_q = vq_out['z_q_combined']
479
- # v13.3: Sanitização após VQ (quantização pode produzir valores extremos).
480
- z_q = torch.nan_to_num(z_q, nan=0.0, posinf=1e4, neginf=-1e4)
481
- # Decoder (com normalização interna configurável via norm_type).
482
- x_recon = self.decoders[name](z_q)
483
- # v13.3: Sanitização final da reconstrução.
484
- x_recon = torch.nan_to_num(x_recon, nan=0.0, posinf=1e4, neginf=-1e4)
485
- recon_loss = F.mse_loss(x_recon, x)
486
-
487
- out['reconstructions'][name] = x_recon
488
- out['codes_top'][name] = vq_out['codes_top']
489
- out['codes_bot'][name] = vq_out['codes_bot']
490
- all_codes_top.append(vq_out['codes_top'])
491
- all_codes_bot.append(vq_out['codes_bot'])
492
- total_vq += vq_out['loss']
493
- total_recon += recon_loss
494
- n += 1
495
-
496
- out['vq_loss'] = total_vq / max(n, 1)
497
- out['recon_loss'] = total_recon / max(n, 1)
498
- out['total_loss'] = out['vq_loss'] + out['recon_loss']
499
- # Use stats already computed in the main loop — avoid redundant VQ forward
500
- # that would sample different random codes and give inconsistent stats.
501
- if vq_out_first_stats is not None:
502
- out['stats'] = vq_out_first_stats
503
- return out
504
-
505
- def cross_modal_translate(
506
- self, x: torch.Tensor, src: str, tgt: str
507
- ) -> torch.Tensor:
508
- """Traduz de uma modalidade para outra via codebook compartilhado."""
509
- # v12.8: forward limpo (sem LayerNorms extras v12.7).
510
- z_e = self.encoders[src](x)
511
- vq_out = self.vq(z_e)
512
- z_q = vq_out['z_q_combined']
513
- return self.decoders[tgt](z_q)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
xeon_runtime.py DELETED
@@ -1,581 +0,0 @@
1
- """xeon_runtime.py — Intel Xeon runtime (V6): AVX512 + AMX_INT8 + IPEX + OneDNN + FP16.
2
-
3
- ═══════════════════════════════════════════════════════════════════════════════
4
- V6 UPGRADE
5
- ═══════════════════════════════════════════════════════════════════════════════
6
-
7
- V5 only set OMP/MKL threads + KMP_AFFINITY. V6 adds:
8
-
9
- 1. MKL_ENABLE_INSTRUCTIONS=AVX512 — forces MKL to dispatch AVX512 kernels
10
- 2. ONEDNN_MAX_CPU_ISA=AMX_INT8 — lets oneDNN use AMX INT8 tiles
11
- 3. DNNL_PRIMITIVE_CACHE_CAPACITY=1024 — large primitive cache (default 1024)
12
- 4. MKL_DYNAMIC=FALSE — disables MKL dynamic thread adjustment
13
- 5. IPEX (intel_extension_for_pytorch) — Intel PyTorch extension
14
- - ipex.optimize(model) on the BiGRU_T model
15
- - torch.cpu.amp.autocast(dtype=torch.float16) for FP16 inference
16
- 6. FP16 benchmark: 8000×8000 matmul, TFLOPS measurement
17
- 7. libvirt AMX activation helper — exposes amx-tile/amx-int8/amx-bf16 to a VM
18
- via host-passthrough CPU mode + feature policy='require'
19
-
20
- The runtime is **always activated** (per user request: "sempre ativar otimização
21
- para Xeon AVX512"). It degrades gracefully if IPEX / libvirt / AMX are not
22
- available, but it never silently skips the optimization step.
23
-
24
- ═══════════════════════════════════════════════════════════════════════════════
25
- USAGE
26
- ═══════════════════════════════════════════════════════════════════════════════
27
-
28
- from bigru_t.utils.xeon_runtime import optimize_xeon_environment
29
- N_CORES = optimize_xeon_environment() # call ONCE, before torch
30
- # ... safe to import torch, ipex, etc. ...
31
-
32
- For VM AMX exposure (requires libvirt-python and root):
33
- from bigru_t.utils.xeon_runtime import ativar_amx_na_vm
34
- ativar_amx_na_vm("my_vm_name")
35
-
36
- ═══════════════════════════════════════════════════════════════════════════════
37
- """
38
- from __future__ import annotations
39
- import os
40
- import sys
41
- import time
42
- import logging
43
- import platform
44
- from typing import Optional, Tuple, Dict, Any
45
-
46
- logger = logging.getLogger(__name__)
47
-
48
- _NUCLEOS_ALOCADOS: Optional[int] = None
49
- _IPEX_AVAILABLE: Optional[bool] = None
50
- _AMX_CAPABLE: Optional[bool] = None
51
- _V6_INIT_DONE: bool = False
52
-
53
-
54
- # ============================================================================
55
- # Helpers
56
- # ============================================================================
57
-
58
- def _detect_physical_cores() -> int:
59
- """Detect physical cores actually available to this process.
60
-
61
- Respects cgroup limits without requiring root. Falls back to logical
62
- cpu count if psutil is unavailable.
63
- """
64
- try:
65
- import psutil
66
- n_phys = psutil.cpu_count(logical=False) or 1
67
- except ImportError:
68
- try:
69
- with open("/proc/cpuinfo", "r") as f:
70
- cores = set()
71
- for line in f:
72
- if line.startswith("core id"):
73
- cores.add(line.strip())
74
- n_phys = len(cores) or 1
75
- except OSError:
76
- n_phys = 1
77
-
78
- try:
79
- n_affine = len(os.sched_getaffinity(0))
80
- n_logical = os.cpu_count() or 1
81
- if n_affine < n_logical:
82
- n_phys = max(1, n_affine // 2)
83
- else:
84
- n_phys = min(n_phys, n_affine)
85
- except (AttributeError, OSError):
86
- pass
87
-
88
- return max(1, n_phys)
89
-
90
-
91
- def _read_cpu_flags() -> str:
92
- try:
93
- with open("/proc/cpuinfo", "r") as f:
94
- for line in f:
95
- if line.startswith("flags"):
96
- return line
97
- except OSError:
98
- pass
99
- return ""
100
-
101
-
102
- def get_avx512_capability() -> Tuple[bool, str]:
103
- """Check if the host CPU supports AVX512 VNNI."""
104
- flags = _read_cpu_flags()
105
- if "avx512_vnni" in flags:
106
- return True, "AVX512_VNNI (full INT8 acceleration)"
107
- elif "avx512f" in flags:
108
- return True, "AVX512F (no VNNI; INT8 falls back to AVX512F)"
109
- elif "avx2" in flags:
110
- return False, "AVX2 only (INT8 quantization works but slower)"
111
- else:
112
- return False, "Legacy SSE (INT8 quantization not recommended)"
113
-
114
-
115
- def get_amx_capability() -> Tuple[bool, str]:
116
- """V6: check if AMX (Advanced Matrix Extensions) is available."""
117
- global _AMX_CAPABLE
118
- flags = _read_cpu_flags()
119
- has_tile = "amx_tile" in flags
120
- has_int8 = "amx_int8" in flags
121
- has_bf16 = "amx_bf16" in flags
122
- if has_tile and has_int8 and has_bf16:
123
- _AMX_CAPABLE = True
124
- return True, "AMX (tile + int8 + bf16) — full AMX acceleration"
125
- elif has_tile:
126
- _AMX_CAPABLE = True
127
- return True, f"AMX tile only (int8={has_int8}, bf16={has_bf16})"
128
- else:
129
- _AMX_CAPABLE = False
130
- return False, "AMX not available (AVX512 path will be used)"
131
-
132
-
133
- def _try_import_ipex() -> Optional[Any]:
134
- """V6: try to import IPEX (Intel Extension for PyTorch).
135
-
136
- Returns the ipex module if available, else None. Caches the result.
137
- """
138
- global _IPEX_AVAILABLE
139
- if _IPEX_AVAILABLE is False:
140
- return None
141
- try:
142
- import intel_extension_for_pytorch as ipex # type: ignore
143
- _IPEX_AVAILABLE = True
144
- return ipex
145
- except (ImportError, AttributeError, OSError) as e:
146
- _IPEX_AVAILABLE = False
147
- if _V6_INIT_DONE is False:
148
- logger.info(f"[Xeon V6] IPEX não disponível: {type(e).__name__}: {e}")
149
- logger.info("[Xeon V6] Continuando com OneDNN/MKL nativo do PyTorch.")
150
- return None
151
-
152
-
153
- # ============================================================================
154
- # FP16 benchmark (V6 — user-provided code)
155
- # ============================================================================
156
-
157
- def benchmark_fp16_matmul(size: int = 8000, warmup: int = 1, iters: int = 3) -> Dict[str, float]:
158
- """V6: FP16 matmul benchmark for Xeon AVX512/AMX.
159
-
160
- Runs `size`×`size` FP16 matmul `iters` times and reports:
161
- - best_time_ms: lowest wall time
162
- - best_tflops: best achieved TFLOPS
163
- - avg_tflops: average TFLOPS
164
-
165
- Returns empty dict if torch unavailable.
166
- """
167
- try:
168
- import torch
169
- except ImportError:
170
- return {}
171
-
172
- results: Dict[str, float] = {}
173
- try:
174
- # Warmup
175
- a = torch.randn(size, size, dtype=torch.float16)
176
- b = torch.randn(size, size, dtype=torch.float16)
177
- for _ in range(warmup):
178
- _ = torch.matmul(a, b)
179
- # Bench
180
- times = []
181
- for _ in range(iters):
182
- t0 = time.perf_counter()
183
- _ = torch.matmul(a, b)
184
- times.append(time.perf_counter() - t0)
185
- best_t = min(times)
186
- avg_t = sum(times) / len(times)
187
- # 2*size^3 FLOPs per matmul (M*N*K)
188
- flops = 2.0 * (size ** 3)
189
- results["best_time_ms"] = best_t * 1000.0
190
- results["avg_time_ms"] = avg_t * 1000.0
191
- results["best_tflops"] = flops / best_t / 1e12
192
- results["avg_tflops"] = flops / avg_t / 1e12
193
- results["matrix_size"] = float(size)
194
- except (RuntimeError, MemoryError) as e:
195
- logger.warning(f"[Xeon V6] FP16 benchmark failed: {e}")
196
- results["error"] = str(e)
197
- return results
198
-
199
-
200
- def benchmark_int8_matmul(size: int = 4096, warmup: int = 1, iters: int = 3) -> Dict[str, float]:
201
- """V6: INT8 matmul benchmark — uses AMX_INT8 when available via oneDNN.
202
-
203
- Falls back to FP32 if INT8 path is unavailable.
204
- """
205
- try:
206
- import torch
207
- except ImportError:
208
- return {}
209
-
210
- results: Dict[str, float] = {}
211
- try:
212
- a = torch.randint(-127, 127, (size, size), dtype=torch.int8)
213
- b = torch.randint(-127, 127, (size, size), dtype=torch.int8)
214
- # Warmup
215
- for _ in range(warmup):
216
- _ = torch.matmul(a.float(), b.float())
217
- times = []
218
- for _ in range(iters):
219
- t0 = time.perf_counter()
220
- _ = torch.matmul(a.float(), b.float())
221
- times.append(time.perf_counter() - t0)
222
- best_t = min(times)
223
- flops = 2.0 * (size ** 3)
224
- results["int8_best_time_ms"] = best_t * 1000.0
225
- results["int8_best_tflops"] = flops / best_t / 1e12
226
- results["int8_matrix_size"] = float(size)
227
- except (RuntimeError, MemoryError) as e:
228
- results["int8_error"] = str(e)
229
- return results
230
-
231
-
232
- # ============================================================================
233
- # Main entry point: optimize_xeon_environment (V6)
234
- # ============================================================================
235
-
236
- def optimize_xeon_environment(
237
- verbose: bool = True,
238
- force_ipex: bool = False,
239
- ) -> int:
240
- """V6: configure Intel Xeon AVX512 + AMX_INT8 + IPEX + OneDNN.
241
-
242
- Always activates — per user requirement "sempre ativar otimização para Xeon
243
- AVX512". Idempotent. Sets every environment variable that influences MKL,
244
- OpenMP, oneDNN, and (optionally) IPEX runtime behavior.
245
-
246
- Args:
247
- verbose: print configuration summary to stdout
248
- force_ipex: if True, raise when IPEX import fails. Default False —
249
- degrade gracefully to native PyTorch oneDNN.
250
-
251
- Returns:
252
- Number of physical cores allocated to this process.
253
- """
254
- global _NUCLEOS_ALOCADOS, _V6_INIT_DONE
255
-
256
- if _NUCLEOS_ALOCADOS is not None and _V6_INIT_DONE:
257
- return _NUCLEOS_ALOCADOS
258
-
259
- n_phys = _detect_physical_cores()
260
-
261
- # ───────────────────────────────────────────────────────────────────────
262
- # V6 — Environment variables (user-provided block)
263
- # ───────────────────────────────────────────────────────────────────────
264
- os.environ["MKL_ENABLE_INSTRUCTIONS"] = "AVX512"
265
- NUM_CORES = str(n_phys)
266
- os.environ["MKL_NUM_THREADS"] = NUM_CORES
267
- os.environ["OMP_NUM_THREADS"] = NUM_CORES
268
- os.environ["MKL_DYNAMIC"] = "FALSE"
269
- os.environ["DNNL_PRIMITIVE_CACHE_CAPACITY"] = "1024"
270
- os.environ["ONEDNN_MAX_CPU_ISA"] = "AMX_INT8"
271
-
272
- # ───────────────────────────────────────────────────────────────────────
273
- # V5 (kept) — OpenMP thread pinning
274
- # ───────────────────────────────────────────────────────────────────────
275
- os.environ.setdefault("KMP_AFFINITY", "granularity=fine,compact,1,0")
276
- os.environ.setdefault("KMP_BLOCKTIME", "1")
277
- os.environ.setdefault("TOKENIZERS_PARALLELISM", "true")
278
-
279
- # ───────────────────────────────────────────────────────────────────────
280
- # PyTorch backend flags
281
- # ───────────────────────────────────────────────────────────────────────
282
- try:
283
- import torch
284
- torch.set_num_threads(n_phys)
285
- try:
286
- torch.set_num_interop_threads(1)
287
- except RuntimeError:
288
- # V6.5: já inicializado (e.g., bigru_t package importou torch antes).
289
- # Silenciosamente ignora — o paralelismo já está configurado.
290
- pass
291
- if hasattr(torch.backends, "mkldnn"):
292
- torch.backends.mkldnn.enabled = True
293
- if hasattr(torch.backends, "quantized"):
294
- try:
295
- torch.backends.quantized.engine = "fbgemm"
296
- except (RuntimeError, AttributeError):
297
- pass
298
- # V6: enable TF32 for Ampere+ / Sapphire Rapids (irrelevant on CPU but
299
- # harmless) and ensure oneDNN verbose is silent.
300
- try:
301
- torch.backends.cuda.matmul.allow_tf32 = True
302
- except AttributeError:
303
- pass
304
- except ImportError:
305
- if verbose:
306
- print("[Xeon V6] WARNING: PyTorch not yet imported — env vars set,"
307
- " call this BEFORE importing torch for full effect.")
308
-
309
- # ───────────────────────────────────────────────────────────────────────
310
- # V6 — IPEX (intel_extension_for_pytorch)
311
- # ───────────────────────────────────────────────────────────────────────
312
- ipex = _try_import_ipex()
313
- if ipex is None and force_ipex:
314
- raise ImportError(
315
- "IPEX (intel_extension_for_pytorch) não disponível, mas force_ipex=True. "
316
- "Instale com: pip install intel-extension-for-pytorch"
317
- )
318
-
319
- # ───────────────────────────────────────────────────────────────────────
320
- # V6 — AMX capability check
321
- # ───────────────────────────────────────────────────────────────────────
322
- amx_ok, amx_desc = get_amx_capability()
323
- avx_ok, avx_desc = get_avx512_capability()
324
-
325
- _NUCLEOS_ALOCADOS = n_phys
326
- _V6_INIT_DONE = True
327
-
328
- if verbose:
329
- print("\n" + "=" * 72)
330
- print(f"[Xeon Runtime V6] Intel Xeon optimization activated")
331
- print("=" * 72)
332
- print(f" Physical cores : {n_phys}")
333
- print(f" MKL_NUM_THREADS : {os.environ['MKL_NUM_THREADS']}")
334
- print(f" OMP_NUM_THREADS : {os.environ['OMP_NUM_THREADS']}")
335
- print(f" MKL_DYNAMIC : {os.environ['MKL_DYNAMIC']}")
336
- print(f" MKL_ENABLE_INSTRUCTIONS: {os.environ['MKL_ENABLE_INSTRUCTIONS']}")
337
- print(f" ONEDNN_MAX_CPU_ISA : {os.environ['ONEDNN_MAX_CPU_ISA']}")
338
- print(f" DNNL_PRIMITIVE_CACHE : {os.environ['DNNL_PRIMITIVE_CACHE_CAPACITY']}")
339
- print(f" KMP_AFFINITY : {os.environ['KMP_AFFINITY']}")
340
- print(f" KMP_BLOCKTIME : {os.environ['KMP_BLOCKTIME']}")
341
- print(f" AVX512 : {avx_desc}")
342
- print(f" AMX : {amx_desc}")
343
- print(f" IPEX : "
344
- f"{'available' if ipex is not None else 'not installed (using native oneDNN)'}")
345
- print("=" * 72 + "\n")
346
-
347
- return n_phys
348
-
349
-
350
- # ============================================================================
351
- # V6 — apply_ipex_optimization (model-level)
352
- # ============================================================================
353
-
354
- def apply_ipex_optimization(model, dtype=None, optimizer=None):
355
- """V6: apply ipex.optimize() to a model.
356
-
357
- Returns (model, optimizer) tuple. If IPEX is not available, returns the
358
- inputs unchanged. The model is modified in-place when IPEX is present.
359
-
360
- Args:
361
- model: torch.nn.Module
362
- dtype: optional torch.dtype for the model (e.g. torch.bfloat16)
363
- optimizer: optional torch.optim.Optimizer to also optimize
364
- """
365
- ipex = _try_import_ipex()
366
- if ipex is None:
367
- return model, optimizer
368
- try:
369
- import torch
370
- if dtype is not None:
371
- model = model.to(dtype)
372
- if optimizer is not None:
373
- model, optimizer = ipex.optimize(model=model, optimizer=optimizer, dtype=dtype)
374
- else:
375
- model = ipex.optimize(model=model, dtype=dtype)
376
- logger.info(f"[Xeon V6] ipex.optimize applied (dtype={dtype})")
377
- except (RuntimeError, AttributeError, TypeError) as e:
378
- logger.warning(f"[Xeon V6] ipex.optimize failed: {e}")
379
- return model, optimizer
380
-
381
-
382
- # ============================================================================
383
- # V6 — FP16 autocast context manager
384
- # ============================================================================
385
-
386
- class fp16_autocast:
387
- """V6: FP16 CPU autocast context manager.
388
-
389
- Uses torch.cpu.amp.autocast(dtype=torch.float16) when available. Falls
390
- back to a no-op context manager if autocast is not supported.
391
-
392
- Usage:
393
- with fp16_autocast():
394
- y = model(x)
395
- """
396
-
397
- def __init__(self, enabled: bool = True):
398
- self.enabled = enabled
399
- self._ctx = None
400
-
401
- def __enter__(self):
402
- if not self.enabled:
403
- return self
404
- try:
405
- import torch
406
- if hasattr(torch.cpu, "amp") and hasattr(torch.cpu.amp, "autocast"):
407
- self._ctx = torch.cpu.amp.autocast(dtype=torch.float16)
408
- self._ctx.__enter__()
409
- except (ImportError, RuntimeError, AttributeError):
410
- self._ctx = None
411
- return self
412
-
413
- def __exit__(self, exc_type, exc_val, exc_tb):
414
- if self._ctx is not None:
415
- self._ctx.__exit__(exc_type, exc_val, exc_tb)
416
- self._ctx = None
417
- return False
418
-
419
-
420
- # ============================================================================
421
- # V6 — libvirt AMX activation helper (user-provided code, integrated)
422
- # ============================================================================
423
-
424
- def ativar_amx_na_vm(nome_vm: str, qemu_uri: str = "qemu:///system") -> bool:
425
- """V6: ativa AMX (amx-tile, amx-int8, amx-bf16) numa VM via libvirt.
426
-
427
- Requer:
428
- - pip install libvirt-python
429
- - libvirtd rodando localmente (qemu:///system)
430
- - permissão de root (ou membro do grupo libvirt)
431
- - CPU física com AMX (verificado por get_amx_capability())
432
-
433
- Implementação:
434
- 1. Conecta ao daemon libvirt
435
- 2. Busca a VM pelo nome
436
- 3. Lê o XML persistente (flag VIR_DOMAIN_XML_INACTIVE = 2)
437
- 4. Garante <cpu mode='host-passthrough'>
438
- 5. Adiciona <feature policy='require' name='amx-tile|int8|bf16'/>
439
- 6. Reescreve o XML via defineXML()
440
-
441
- Retorna True se a VM foi atualizada com sucesso, False caso contrário.
442
- Requer reboot da VM para aplicar.
443
-
444
- Args:
445
- nome_vm: nome da máquina virtual no libvirt
446
- qemu_uri: URI do libvirt (default: qemu:///system)
447
-
448
- Raises:
449
- ImportError: se libvirt-python não estiver instalado
450
- RuntimeError: se a conexão com libvirt falhar
451
- """
452
- try:
453
- import libvirt # type: ignore
454
- except ImportError as e:
455
- raise ImportError(
456
- "libvirt-python não instalado. Rode: pip install libvirt-python "
457
- "(também requer libvirt-dev no sistema: apt install libvirt-dev)"
458
- ) from e
459
-
460
- try:
461
- import xml.etree.ElementTree as ET
462
- except ImportError:
463
- return False
464
-
465
- # Pré-checa AMX no host físico
466
- amx_ok, amx_desc = get_amx_capability()
467
- if not amx_ok:
468
- print(f"[AMX VM] Host físico não tem AMX ({amx_desc}).")
469
- print(" Não adianta ativar AMX na VM — o host precisa suportar.")
470
- return False
471
-
472
- try:
473
- conn = libvirt.open(qemu_uri)
474
- if conn is None:
475
- print(f"[AMX VM] Falha ao abrir conexão com {qemu_uri}")
476
- return False
477
-
478
- try:
479
- dom = conn.lookupByName(nome_vm)
480
- except libvirt.libvirtError:
481
- print(f"[AMX VM] VM '{nome_vm}' não encontrada.")
482
- conn.close()
483
- return False
484
-
485
- xml_atual = dom.XMLDesc(2) # VIR_DOMAIN_XML_INACTIVE
486
- root = ET.fromstring(xml_atual)
487
- cpu_elem = root.find("cpu")
488
-
489
- if cpu_elem is None:
490
- cpu_elem = ET.SubElement(root, "cpu", mode="host-passthrough")
491
- print("[AMX VM] Tag <cpu> criada com mode='host-passthrough'.")
492
- else:
493
- cpu_elem.set("mode", "host-passthrough")
494
- print("[AMX VM] CPU mode atualizado para host-passthrough.")
495
-
496
- flags_para_adicionar = ["amx-tile", "amx-int8", "amx-bf16"]
497
- added = []
498
- for flag in flags_para_adicionar:
499
- existing = cpu_elem.find(f"./feature[@name='{flag}']")
500
- if existing is None:
501
- ET.SubElement(cpu_elem, "feature", policy="require", name=flag)
502
- added.append(flag)
503
- print(f"[AMX VM] Feature adicionada: {flag}")
504
-
505
- novo_xml = ET.tostring(root, encoding="utf-8").decode("utf-8")
506
- conn.defineXML(novo_xml)
507
- print(f"[AMX VM] ✓ AMX ativado no XML da VM '{nome_vm}'. Reinicie a VM para aplicar.")
508
- conn.close()
509
- return True
510
-
511
- except libvirt.libvirtError as e:
512
- print(f"[AMX VM] Erro libvirt: {e}")
513
- return False
514
- except Exception as e:
515
- print(f"[AMX VM] Erro inesperado: {e}")
516
- return False
517
-
518
-
519
- # ============================================================================
520
- # Compatibility helpers (V5 API preserved)
521
- # ============================================================================
522
-
523
- def get_allocated_cores() -> int:
524
- """Return the number of cores allocated by `optimize_xeon_environment`."""
525
- return _NUCLEOS_ALOCADOS or 0
526
-
527
-
528
- def make_ort_session_options():
529
- """Build onnxruntime.SessionOptions tuned for Xeon AVX512/AMX."""
530
- import onnxruntime as ort # type: ignore
531
-
532
- n_cores = _NUCLEOS_ALOCADOS or _detect_physical_cores()
533
-
534
- opts = ort.SessionOptions()
535
- opts.intra_op_num_threads = n_cores
536
- opts.inter_op_num_threads = 1
537
- opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
538
- opts.enable_cpu_mem_arena = True
539
- return opts
540
-
541
-
542
- def get_xeon_status() -> Dict[str, Any]:
543
- """V6: return a snapshot of all Xeon runtime flags + capabilities.
544
-
545
- Useful for logging inside the training script.
546
- """
547
- amx_ok, amx_desc = get_amx_capability()
548
- avx_ok, avx_desc = get_avx512_capability()
549
- return {
550
- "version": "V6",
551
- "physical_cores": _NUCLEOS_ALOCADOS or _detect_physical_cores(),
552
- "env": {
553
- "MKL_ENABLE_INSTRUCTIONS": os.environ.get("MKL_ENABLE_INSTRUCTIONS"),
554
- "MKL_NUM_THREADS": os.environ.get("MKL_NUM_THREADS"),
555
- "OMP_NUM_THREADS": os.environ.get("OMP_NUM_THREADS"),
556
- "MKL_DYNAMIC": os.environ.get("MKL_DYNAMIC"),
557
- "DNNL_PRIMITIVE_CACHE_CAPACITY": os.environ.get("DNNL_PRIMITIVE_CACHE_CAPACITY"),
558
- "ONEDNN_MAX_CPU_ISA": os.environ.get("ONEDNN_MAX_CPU_ISA"),
559
- "KMP_AFFINITY": os.environ.get("KMP_AFFINITY"),
560
- "KMP_BLOCKTIME": os.environ.get("KMP_BLOCKTIME"),
561
- },
562
- "avx512": {"supported": avx_ok, "desc": avx_desc},
563
- "amx": {"supported": amx_ok, "desc": amx_desc},
564
- "ipex_available": _IPEX_AVAILABLE is True,
565
- "init_done": _V6_INIT_DONE,
566
- }
567
-
568
-
569
- __all__ = [
570
- "optimize_xeon_environment",
571
- "apply_ipex_optimization",
572
- "fp16_autocast",
573
- "benchmark_fp16_matmul",
574
- "benchmark_int8_matmul",
575
- "ativar_amx_na_vm",
576
- "get_avx512_capability",
577
- "get_amx_capability",
578
- "get_xeon_status",
579
- "get_allocated_cores",
580
- "make_ort_session_options",
581
- ]