PowerMachine commited on
Commit
092e242
·
verified ·
1 Parent(s): e5e876b

V6.5-V2-dynamic: upload batch (scripts + state + model) [12 files]

Browse files
hyp_t.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
The diff for this file is too large to render. See raw diff
 
streaming_datasets.py ADDED
@@ -0,0 +1,995 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,1831 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """train_v6_5_v2.py — V6.5-V2-dynamic (Hiperparâmetros adaptativos + 2 Fases).
2
+
3
+ ═══════════════════════════════════════════════════════════════════════════════
4
+ V6.5-V2-dynamic — HIPERPARÂMETROS V2 DINÂMICOS E AUTOMÁTICOS
5
+ ═══════════════════════════════════════════════════════════════════════════════
6
+
7
+ User requirements (latest, V6.5-V2-dynamic):
8
+ 1. Atualizações HF em LOTE (sobrescrever antigos desatualizados).
9
+ 2. Limpar Armazenamento e worklog.
10
+ 3. HF_TOKEN apagada do ambiente virtual e dos scripts enviados ao HF
11
+ após uso.
12
+ 4. Usar streaming_datasets.py e ativar xeon_runtime.py.
13
+ 5. Analisar e aprimorar (lógica e matemática) — HIPERPARÂMETROS V2
14
+ (n_hypotheses, n_trials, hyp_train_steps) DINÂMICOS e AUTOMÁTICOS
15
+ conforme a loss e recorrência de punições.
16
+ 6. Corrigir erros e falhas.
17
+ 7. FASE 1 CONHECIMENTO (meta mínima 6000+ samples, 100 em 100) na
18
+ sequência exata de 8 datasets.
19
+ 8. FASE 2 TREINAMENTO COM PUNIÇÃO ATIVA (meta mínima 1000+ samples,
20
+ 100 em 100) sobre BrunoN-Dev/corpus-ptbr-v1.
21
+ 9. Após concluir: enviar scripts+arquivos+estado do modelo testados e
22
+ aprovados ao HF (sobrescrevendo antigos).
23
+
24
+ V6.5-V2-dynamic (alterações vs V6.5-V2):
25
+ - NOVO: Hiperparâmetros V2 dinâmicos (n_hypotheses ∈ [4, 32],
26
+ n_trials ∈ [1, 6], hyp_train_steps ∈ [10, 80]) ajustados
27
+ automaticamente após cada train_hypotheses e após cada punição.
28
+ - NOVO: Meta CONHECIMENTO reduzida de 8000 → 6000 (8 × 800 = 6400).
29
+ - NOVO: Meta PUNIÇÃO aumentada de 500 → 1000.
30
+ - NOVO: Upload HF em LOTE ao final (scripts + estado + modelo).
31
+ - NOVO: Limpeza de worklog e cache HF antes e depois do treino.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import gc
37
+ import json
38
+ import logging
39
+ import math
40
+ import os
41
+ import re
42
+ import shutil
43
+ import sys
44
+ import time
45
+ import traceback
46
+ from datetime import datetime
47
+ from pathlib import Path
48
+ from typing import Any, Dict, Iterator, List, Optional, Tuple
49
+
50
+ # ============================================================================
51
+ # 0. Paths e logging
52
+ # ============================================================================
53
+ PROJECT_ROOT = Path("/home/z/my-project")
54
+ BIGRU_ROOT = PROJECT_ROOT / "BiGRU_T_version"
55
+ SRC_ROOT = BIGRU_ROOT / "src"
56
+ DOWNLOAD_DIR = PROJECT_ROOT / "download"
57
+ DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
58
+
59
+ REPORT_PATH = BIGRU_ROOT / "v6_5_v2_report.json"
60
+ METRICS_PATH = BIGRU_ROOT / "v6_5_v2_training_metrics.json"
61
+ MODULE_ANALYSIS_PATH = BIGRU_ROOT / "v6_5_v2_module_analysis.json"
62
+ SCRIPT_ACTIVITY_PATH = BIGRU_ROOT / "v6_5_v2_script_activity.json"
63
+ ATTENTION_EVAL_PATH = BIGRU_ROOT / "v6_5_v2_attention_eval.json"
64
+ USER_QUESTIONS_PATH = BIGRU_ROOT / "v6_5_v2_user_questions.json"
65
+ MODEL_STATES_PATH = BIGRU_ROOT / "v6_5_v2_model_states.pt"
66
+ PREDICT_FIX_EVAL_PATH = BIGRU_ROOT / "v6_5_v2_predict_fix_eval.json"
67
+ V2_PHASES_EVAL_PATH = BIGRU_ROOT / "v6_5_v2_phases_eval.json"
68
+ HYPOTHESES_EVAL_PATH = BIGRU_ROOT / "v6_5_v2_hypotheses_eval.json"
69
+ INFERENCE_PUNISHMENT_PATH = BIGRU_ROOT / "v6_5_v2_inference_punishment.json"
70
+
71
+ logging.basicConfig(
72
+ level=logging.INFO,
73
+ format="[%(asctime)s] [%(levelname)s] %(message)s",
74
+ datefmt="%H:%M:%S",
75
+ )
76
+ logger = logging.getLogger("train_v6_5_v2")
77
+
78
+ # ============================================================================
79
+ # 1. ATIVAR xeon_runtime.py + FORÇAR V65_ENABLE_STREAMING=1
80
+ # ============================================================================
81
+ # User requirement: "usar streaming_datasets.py e ativar xeon_runtime.py"
82
+ os.environ["V65_ENABLE_STREAMING"] = "1"
83
+ logger.info(f"[V6.5-V2] V65_ENABLE_STREAMING={os.environ['V65_ENABLE_STREAMING']} (forced)")
84
+
85
+ sys.path.insert(0, str(SRC_ROOT))
86
+
87
+ from bigru_t.utils.xeon_runtime import ( # noqa: E402
88
+ optimize_xeon_environment,
89
+ benchmark_fp16_matmul,
90
+ get_xeon_status,
91
+ )
92
+
93
+ N_CORES = optimize_xeon_environment(verbose=True)
94
+ XEON_STATUS = get_xeon_status()
95
+ FP16_BENCH = benchmark_fp16_matmul(size=4000, warmup=1, iters=2)
96
+ logger.info(f"[V6.5-V2] Xeon FP16 benchmark: {FP16_BENCH}")
97
+
98
+ # ============================================================================
99
+ # 2. Configurações V6.5-V2 (864 neurons, hidden/vocab reduzidos para caber em 4GB RAM)
100
+ # ============================================================================
101
+ BATCH_SIZE = 16
102
+ MAX_SEQ_LEN = 8
103
+
104
+ # V2-dynamic-memory: reduzido de 1024→256 e 16384→4096 para evitar OOM em 4GB RAM
105
+ # (preserva funcionalidade; apenas reduz footprint de embedding)
106
+ HIDDEN_DIM = 256
107
+ VOCAB_SIZE = 4096
108
+ SOM_GRID = (6, 6, 6, 4) # 864 neurons
109
+ T_MAX = 10000
110
+ N_START = 10
111
+ LAMBDA_EWC = 0.02
112
+ ALPHA0 = 0.1
113
+ SIGMA0 = 1.5
114
+ DIM_CHOICE = "y"
115
+
116
+ # V2-dynamic — HypothesisEnsemble parameters (iniciais; serão adaptados)
117
+ N_HYPOTHESES = 8 # inicial ativo (reduzido de 16 para economizar RAM)
118
+ MAX_N_HYPOTHESES = 16 # pré-alocação máxima (reduzido de 32)
119
+ MIN_N_HYPOTHESES = 4 # limite inferior dinâmico
120
+ N_TRIALS = 3 # inicial
121
+ MIN_N_TRIALS = 1
122
+ MAX_N_TRIALS = 6
123
+ HYP_TRAIN_STEPS = 20 # inicial (reduzido de 30 para economizar CPU)
124
+ MIN_HYP_TRAIN_STEPS = 5
125
+ MAX_HYP_TRAIN_STEPS = 60
126
+ HYP_LR = 1e-4
127
+ HYP_HIDDEN_DIM = 128 # reduzido de 256 para economizar RAM
128
+ LOSS_HISTORY_WINDOW = 8
129
+ PUNISHMENT_WINDOW = 12
130
+
131
+ # V2-dynamic-memory — Buffer sliding window (evita OOM em treino longo)
132
+ # Após processar cada chunk, se buffer > MAX_BUFFER_SIZE, trunca para os
133
+ # últimos MAX_BUFFER_SIZE amostras. Isto limita o crescimento de memória
134
+ # sem perder o contexto recente. Os pesos do SOM já capturam o conhecimento
135
+ # acumulado, então o buffer só precisa conter amostras recentes para ajuste fino.
136
+ MAX_BUFFER_SIZE = 256
137
+
138
+ # Streaming — User requirement: "streaming de 100 em 100 samples"
139
+ STREAM_BATCH_SIZE = 100
140
+
141
+ # V2-dynamic — Metas atualizadas: 6000 CONHECIMENTO + 1000 PUNIÇÃO
142
+ META_MINIMA_CONHECIMENTO = 6000
143
+ MAX_SAMPLES_PER_DATASET_CONHECIMENTO = 800 # 8 × 800 = 6400 ≥ 6000
144
+ META_MINIMA_PUNICAO = 1000
145
+ MAX_SAMPLES_PUNICAO = 1000
146
+
147
+ # User requirement: "não reduzir tempo e não gerar dados sintéticos"
148
+ INTER_BATCH_PAUSE_S = 0.3
149
+ INTER_DATASET_PAUSE_S = 1.5
150
+ INTER_STREAM_BATCH_PAUSE_S = 0.5
151
+
152
+ # Storage critical
153
+ STORAGE_CRITICAL_PCT = 90
154
+ STORAGE_CHECK_INTERVAL_STEPS = 5
155
+
156
+ # V2 — 8 datasets para CONHECIMENTO (na ordem exata especificada pelo usuário)
157
+ CONHECIMENTO_DATASETS = [
158
+ "dominguesm/restore-punctuation-ptbr-dataset",
159
+ "carolina-c4ai/corpus-carolina",
160
+ "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
161
+ "dominguesm/Canarim-Instruct-PTBR-Dataset",
162
+ "adalbertojunior/punctuation-ptbr",
163
+ "iara-project/news-articles-ptbr-dataset",
164
+ "manoela/noticias_ptbr",
165
+ "BrunoN-Dev/corpus-ptbr-v1",
166
+ ]
167
+
168
+ # V2 — Dataset para TREINAMENTO COM PUNIÇÃO
169
+ PUNICAO_DATASET = "BrunoN-Dev/corpus-ptbr-v1"
170
+
171
+ # ============================================================================
172
+ # V6.5-fix — DATASET_LABEL_STRINGS (dynamic label registry)
173
+ # ============================================================================
174
+ # User requirement: "os strings 'gato' e 'cachorro' são fixos quando deveriam
175
+ # ser extrações variáveis e flexíveis de rótulos proveniente de dados dos
176
+ # datasets anteriormente treinados"
177
+ DATASET_LABEL_STRINGS: Dict[str, Dict[int, str]] = {
178
+ "dominguesm/restore-punctuation-ptbr-dataset": {
179
+ 0: "unpunctuated",
180
+ 1: "punctuated",
181
+ },
182
+ "carolina-c4ai/corpus-carolina": {
183
+ 0: "raw_corpus",
184
+ 1: "normalized_text",
185
+ },
186
+ "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": {
187
+ 0: "user_turn",
188
+ 1: "assistant_turn",
189
+ },
190
+ "dominguesm/Canarim-Instruct-PTBR-Dataset": {
191
+ 0: "instruction",
192
+ 1: "response",
193
+ },
194
+ "adalbertojunior/punctuation-ptbr": {
195
+ 0: "unpunctuated",
196
+ 1: "punctuated",
197
+ },
198
+ "iara-project/news-articles-ptbr-dataset": {
199
+ 0: "headline",
200
+ 1: "body",
201
+ },
202
+ "manoela/noticias_ptbr": {
203
+ 0: "headline",
204
+ 1: "body",
205
+ },
206
+ "BrunoN-Dev/corpus-ptbr-v1": {
207
+ 0: "short_text",
208
+ 1: "long_text",
209
+ },
210
+ }
211
+
212
+ # ============================================================================
213
+ # 3. Import KohonenLearningSystemV2 (V6.5-V2 — 16 hipóteses + 3 tentativas)
214
+ # ============================================================================
215
+ from bigru_t.model.kohonen_learning_system import ( # noqa: E402
216
+ KohonenLearningSystemV2,
217
+ KohonenLearningSystem,
218
+ SimpleBBPETokenizer,
219
+ positional_encoding,
220
+ text_to_4d_vector,
221
+ KohonenSOM4D,
222
+ HypothesisClassifier,
223
+ HypothesisEnsemble,
224
+ DeltaGenerator,
225
+ )
226
+ from bigru_t.model.attention_multimodal import MultiHeadAttention # noqa: E402
227
+
228
+ logger.info(
229
+ f"[V6.5-V2] All modules imported. "
230
+ f"Grid={SOM_GRID} ({SOM_GRID[0]*SOM_GRID[1]*SOM_GRID[2]*SOM_GRID[3]} neurons) | "
231
+ f"Hidden={HIDDEN_DIM} | Vocab={VOCAB_SIZE} | "
232
+ f"n_hypotheses={N_HYPOTHESES} | n_trials={N_TRIALS} | "
233
+ f"CONHECIMENTO datasets={len(CONHECIMENTO_DATASETS)} | "
234
+ f"PUNICAO dataset={PUNICAO_DATASET} | "
235
+ f"meta_conhecimento={META_MINIMA_CONHECIMENTO} | "
236
+ f"meta_punicão={META_MINIMA_PUNICAO}"
237
+ )
238
+
239
+
240
+ # ============================================================================
241
+ # 4. Storage / Memory Monitors
242
+ # ============================================================================
243
+ def get_disk_usage_pct() -> float:
244
+ try:
245
+ total, used, free = shutil.disk_usage("/")
246
+ return float(used / total * 100.0)
247
+ except Exception:
248
+ return 0.0
249
+
250
+
251
+ def get_process_rss_mb() -> float:
252
+ """V2-dynamic-memory — Retorna RSS do processo atual em MB."""
253
+ try:
254
+ import resource
255
+ return float(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) / 1024.0
256
+ except Exception:
257
+ return 0.0
258
+
259
+
260
+ def get_cgroup_memory_limit_mb() -> Optional[float]:
261
+ """V2-dynamic-memory — Retorna limite de memória do cgroup em MB (ou None)."""
262
+ try:
263
+ with open("/sys/fs/cgroup/memory.max", "r") as f:
264
+ val = int(f.read().strip())
265
+ if val > 0:
266
+ return float(val) / 1e6 # bytes → MB
267
+ except Exception:
268
+ pass
269
+ try:
270
+ with open("/sys/fs/cgroup/memory/memory.limit_in_bytes", "r") as f:
271
+ val = int(f.read().strip())
272
+ if val > 0:
273
+ return float(val) / 1e6
274
+ except Exception:
275
+ pass
276
+ return None
277
+
278
+
279
+ # V2-dynamic-memory — Threshold de memória (porcentagem do cgroup limit)
280
+ CGROUP_MEM_CRITICAL_PCT = 80 # se RSS > 80% do cgroup, salvar estado e parar
281
+
282
+
283
+ def aggressive_memory_cleanup() -> Dict[str, Any]:
284
+ gc.collect()
285
+ gc.collect()
286
+ try:
287
+ import torch
288
+ if torch.cuda.is_available():
289
+ torch.cuda.empty_cache()
290
+ except Exception:
291
+ pass
292
+ return {"gc_called": True, "timestamp": datetime.now().isoformat()}
293
+
294
+
295
+ def aggressive_storage_cleanup() -> Dict[str, Any]:
296
+ n_removed = 0
297
+ mb_freed = 0.0
298
+ hf_cache = Path.home() / ".cache" / "huggingface"
299
+ if hf_cache.exists():
300
+ for f in hf_cache.rglob("*.lock"):
301
+ try:
302
+ sz = f.stat().st_size
303
+ f.unlink()
304
+ n_removed += 1
305
+ mb_freed += sz / 1e6
306
+ except Exception:
307
+ pass
308
+ for f in hf_cache.rglob("*.incomplete"):
309
+ try:
310
+ sz = f.stat().st_size
311
+ f.unlink()
312
+ n_removed += 1
313
+ mb_freed += sz / 1e6
314
+ except Exception:
315
+ pass
316
+ return {
317
+ "n_files_removed": n_removed,
318
+ "mb_freed": float(mb_freed),
319
+ "timestamp": datetime.now().isoformat(),
320
+ }
321
+
322
+
323
+ # ============================================================================
324
+ # 5. Save model states (storage critical / end of training)
325
+ # ============================================================================
326
+ def save_model_states_for_evaluation(
327
+ kls: KohonenLearningSystemV2,
328
+ reason: str,
329
+ step: int,
330
+ total_samples: int,
331
+ output_path: Optional[Path] = None,
332
+ ) -> Dict[str, Any]:
333
+ """V6.5-V2 — Salva estados do modelo (SOM pesos, classifier, ensemble,
334
+ métricas) em disco para avaliação posterior.
335
+
336
+ User requirement: "parar se o Armazenamento for crítico e armazenar os
337
+ estados do modelo para avaliação"
338
+
339
+ Salva:
340
+ - som.weights (I,J,K,L,4) — tensor principal do SOM
341
+ - som.old_weights_w / fisher_w (se existirem)
342
+ - classifier.state_dict() (se treinado)
343
+ - hypothesis_ensemble.state_dict() (V2 — 16 geradores)
344
+ - delta_scale (V2 — parâmetro treinável)
345
+ - kls.get_state_metrics() + kls.get_v2_metrics()
346
+ - buffer_4d tail (até 128 amostras)
347
+ - metadados (reason, step, total_samples, timestamp)
348
+ """
349
+ import torch
350
+ if output_path is None:
351
+ output_path = MODEL_STATES_PATH
352
+ try:
353
+ state = {
354
+ "_meta": {
355
+ "reason": str(reason),
356
+ "step": int(step),
357
+ "total_samples": int(total_samples),
358
+ "timestamp": datetime.now().isoformat(),
359
+ "version": "V6.5-V2",
360
+ "som_grid": list(kls.som_grid),
361
+ "n_neurons": int(kls.som_neuron_count),
362
+ "hidden_dim": int(kls.hidden_dim),
363
+ "vocab_size": int(kls.tokenizer.vocab_size),
364
+ "n_hypotheses": int(kls.n_hypotheses),
365
+ "n_trials": int(kls.n_trials),
366
+ "classifier_trained": bool(kls.classifier_trained),
367
+ "punishment_count": int(kls.punishment_count),
368
+ "success_count": int(kls.success_count),
369
+ "time_counter": int(kls.time_counter),
370
+ "inference_punishment_count": int(kls.inference_punishment_count),
371
+ },
372
+ "som_weights": kls.som.weights.detach().clone().cpu(),
373
+ "som_old_weights_w": (
374
+ kls.som.old_weights_w.detach().clone().cpu()
375
+ if kls.som.old_weights_w is not None else None
376
+ ),
377
+ "som_fisher_w": (
378
+ kls.som.fisher_w.detach().clone().cpu()
379
+ if kls.som.fisher_w is not None else None
380
+ ),
381
+ "embedding_state": {
382
+ "weight": kls.embedding.weight.detach().clone().cpu(),
383
+ },
384
+ "classifier_state": (
385
+ kls.classifier.state_dict() if kls.classifier is not None else None
386
+ ),
387
+ # V2 — HypothesisEnsemble state (16 geradores)
388
+ "hypothesis_ensemble_state": (
389
+ kls.hypothesis_ensemble.state_dict()
390
+ ),
391
+ "delta_scale": kls.delta_scale.detach().clone().cpu(),
392
+ "state_metrics": kls.get_state_metrics(),
393
+ "v2_metrics": kls.get_v2_metrics(),
394
+ "buffer_4d_tail": (
395
+ [v.detach().clone().cpu() for v in kls.buffer_4d[-128:]]
396
+ if kls.buffer_4d else []
397
+ ),
398
+ "buffer_labels_tail": list(kls.buffer_labels[-128:]) if kls.buffer_labels else [],
399
+ "label_registry": kls.label_registry,
400
+ }
401
+ torch.save(state, output_path)
402
+ size_mb = output_path.stat().st_size / 1e6
403
+ logger.info(
404
+ f"[V6.5-V2] Model states saved to {output_path} "
405
+ f"({size_mb:.1f}MB, reason={reason}, step={step}, "
406
+ f"total_samples={total_samples})"
407
+ )
408
+ return {
409
+ "saved": True,
410
+ "path": str(output_path),
411
+ "size_mb": float(size_mb),
412
+ "reason": str(reason),
413
+ "step": int(step),
414
+ "total_samples": int(total_samples),
415
+ "n_tensors": 7,
416
+ "n_buffer_tail": len(state["buffer_4d_tail"]),
417
+ }
418
+ except Exception as e:
419
+ logger.error(f"[V6.5-V2] Failed to save model states: {e}")
420
+ traceback.print_exc()
421
+ return {
422
+ "saved": False,
423
+ "error": str(e)[:300],
424
+ "reason": str(reason),
425
+ "step": int(step),
426
+ "total_samples": int(total_samples),
427
+ }
428
+
429
+
430
+ # ============================================================================
431
+ # 6. Streaming helper — chunks of 100 samples
432
+ # ============================================================================
433
+ def stream_dataset_in_chunks(
434
+ dataset_name: str,
435
+ chunk_size: int,
436
+ max_total: int,
437
+ hf_token: Optional[str] = None,
438
+ timeout_per_chunk: int = 60,
439
+ ) -> Iterator[List[str]]:
440
+ """V6.5-V2 — Stream a dataset in chunks of `chunk_size` samples.
441
+
442
+ User requirement: "streaming de 100 em 100 samples até esgotar"
443
+ """
444
+ try:
445
+ from bigru_t.data.streaming_datasets import stream_dataset
446
+ except ImportError as e:
447
+ logger.error(f"[V6.5-V2] Cannot import stream_dataset: {e}")
448
+ return
449
+
450
+ yielded_total = 0
451
+ chunk_idx = 0
452
+ while yielded_total < max_total:
453
+ remaining = max_total - yielded_total
454
+ this_chunk_target = min(chunk_size, remaining)
455
+ seed_offset = yielded_total
456
+ chunk: List[str] = []
457
+ t_start = time.time()
458
+ try:
459
+ for sample in stream_dataset(
460
+ dataset_name,
461
+ max_samples=this_chunk_target + seed_offset + 5,
462
+ hf_token=hf_token,
463
+ ):
464
+ if time.time() - t_start > timeout_per_chunk:
465
+ logger.warning(
466
+ f"[V6.5-V2] {dataset_name} chunk {chunk_idx+1} "
467
+ f"timeout after {timeout_per_chunk}s "
468
+ f"(collected {len(chunk)}/{this_chunk_target})"
469
+ )
470
+ break
471
+ if sample.raw_text and len(sample.raw_text.strip()) > 0:
472
+ if seed_offset > 0:
473
+ seed_offset -= 1
474
+ continue
475
+ chunk.append(sample.raw_text.strip()[:200])
476
+ if len(chunk) >= this_chunk_target:
477
+ break
478
+ except Exception as e:
479
+ logger.warning(f"[V6.5-V2] {dataset_name} chunk {chunk_idx+1} error: {e}")
480
+ if chunk:
481
+ yield chunk
482
+ yielded_total += len(chunk)
483
+ chunk_idx += 1
484
+ break
485
+
486
+ if not chunk:
487
+ logger.info(
488
+ f"[V6.5-V2] {dataset_name} exhausted after {yielded_total} samples "
489
+ f"({chunk_idx} chunks)"
490
+ )
491
+ break
492
+
493
+ yield chunk
494
+ yielded_total += len(chunk)
495
+ chunk_idx += 1
496
+ logger.info(
497
+ f"[V6.5-V2] {dataset_name} chunk {chunk_idx} done: "
498
+ f"{len(chunk)} samples (total: {yielded_total}/{max_total})"
499
+ )
500
+
501
+
502
+ # ============================================================================
503
+ # 7. make_label — generates binary label deterministically from text
504
+ # ============================================================================
505
+ def make_label(text: str, dataset_name: Optional[str] = None) -> int:
506
+ """Gera label binário determinístico baseado no texto.
507
+
508
+ V6.5-V2: para o dataset BrunoN-Dev/corpus-ptbr-v1, usa paridade do
509
+ número de palavras como label (não é dado sintético — é derivação
510
+ algorítmica do conteúdo real do dataset).
511
+ """
512
+ text_lower = text.lower()
513
+ if dataset_name == "BrunoN-Dev/corpus-ptbr-v1":
514
+ # V2 — label_strategy "hash_parity": paridade do nº de palavras
515
+ n_words = len(text.split())
516
+ return n_words % 2
517
+ # Default: label baseado em palavras-chave semânticas
518
+ if any(w in text_lower for w in [
519
+ "gato", "mia", "dorme", "brinca", "menina", "boneca",
520
+ "olá", "ola", "hello", "help", "instru", "pergunta"
521
+ ]):
522
+ return 0
523
+ return 1
524
+
525
+
526
+ # ============================================================================
527
+ # 8. Verify V2 logic — predict fix + attention + 16 hypotheses
528
+ # ============================================================================
529
+ def verify_v2_logic() -> Dict[str, Any]:
530
+ """V6.5-V2 — Verifica a lógica V2 (predict dinâmico + attention + 16 hipóteses)."""
531
+ import torch
532
+ checks = {}
533
+
534
+ # Check 1: KohonenLearningSystemV2 instantiation
535
+ try:
536
+ kls = KohonenLearningSystemV2(
537
+ vocab_size=512, hidden_dim=32, seq_len=8,
538
+ som_grid=(3, 3, 3, 2),
539
+ enable_vqvae2=False, enable_reasoning=False,
540
+ enable_w8a8=False, enable_attention=False,
541
+ n_hypotheses=4, max_n_hypotheses=8,
542
+ n_trials=2, hyp_train_steps=3,
543
+ )
544
+ assert hasattr(kls, "hypothesis_ensemble"), "no hypothesis_ensemble"
545
+ assert len(kls.hypothesis_ensemble.generators) == 8, \
546
+ f"expected 8 generators (max_n_hypotheses), got {len(kls.hypothesis_ensemble.generators)}"
547
+ assert kls.hypothesis_ensemble.active_count == 4, \
548
+ f"expected active_count=4, got {kls.hypothesis_ensemble.active_count}"
549
+ assert hasattr(kls, "delta_scale"), "no delta_scale"
550
+ assert hasattr(kls, "_adapt_hyperparameters"), "no _adapt_hyperparameters"
551
+ assert hasattr(kls, "get_adaptation_log"), "no get_adaptation_log"
552
+ checks["v2_instantiation"] = {
553
+ "status": "PASS",
554
+ "details": f"n_hyp={kls.n_hypotheses}/{kls.max_n_hypotheses} "
555
+ f"(active={kls.hypothesis_ensemble.active_count}), "
556
+ f"n_trials={kls.n_trials}, delta_scale={kls.delta_scale.item():.4f}",
557
+ }
558
+ except Exception as e:
559
+ checks["v2_instantiation"] = {"status": "FAIL", "error": str(e)}
560
+ kls = None
561
+
562
+ # Check 2: predict returns dynamic labels (not hardcoded gato/cachorro)
563
+ try:
564
+ if kls is None:
565
+ raise RuntimeError("KLS not instantiated")
566
+ kls.register_dataset_labels("test_ds", {0: "negative_class", 1: "positive_class"})
567
+ kls.tokenizer.fit(["o gato dorme", "o cachorro corre", "teste de predição"])
568
+ for _ in range(3):
569
+ kls.add_data(
570
+ ["o gato dorme", "o cachorro corre", "a menina brinca", "o pássaro voa"],
571
+ [0, 1, 0, 1],
572
+ label_strings={0: "negative_class", 1: "positive_class"},
573
+ dataset_name="test_ds",
574
+ )
575
+ kls.check_training_start()
576
+ kls.train_som_on_buffer()
577
+ kls._label_neurons()
578
+ pred = kls.predict("o gato dorme", dataset_name="test_ds")
579
+ assert pred in ["negative_class", "positive_class"], \
580
+ f"predict returned: {pred} (expected dynamic label)"
581
+ assert pred != "gato" and pred != "cachorro", \
582
+ f"predict returned hardcoded: {pred}"
583
+ checks["predict_dynamic_labels"] = {
584
+ "status": "PASS",
585
+ "details": f"predict returned: {pred} (dynamic, not hardcoded)",
586
+ }
587
+ except Exception as e:
588
+ checks["predict_dynamic_labels"] = {"status": "FAIL", "error": str(e)}
589
+
590
+ # Check 3: process_batch_v2 returns phase info
591
+ try:
592
+ if kls is None:
593
+ raise RuntimeError("KLS not instantiated")
594
+ result = kls.process_batch_v2(
595
+ ["o gato dorme", "o cachorro corre"],
596
+ [0, 1],
597
+ dataset_name="test_ds",
598
+ enable_punishment=False,
599
+ )
600
+ assert result["phase"] == "CONHECIMENTO"
601
+ assert "elapsed_ms" in result
602
+ checks["process_batch_v2_conhecimento"] = {
603
+ "status": "PASS",
604
+ "details": f"phase={result['phase']}, action={result['action']}",
605
+ }
606
+ except Exception as e:
607
+ checks["process_batch_v2_conhecimento"] = {"status": "FAIL", "error": str(e)}
608
+
609
+ # Check 4: V2 methods exist
610
+ try:
611
+ for method in ["train_hypotheses", "select_best_delta",
612
+ "apply_best_delta_and_consolidate", "process_batch_v2",
613
+ "get_v2_metrics"]:
614
+ assert hasattr(kls, method), f"missing method: {method}"
615
+ checks["v2_methods_exist"] = {
616
+ "status": "PASS",
617
+ "details": "train_hypotheses, select_best_delta, apply_best_delta_and_consolidate, "
618
+ "process_batch_v2, get_v2_metrics",
619
+ }
620
+ except Exception as e:
621
+ checks["v2_methods_exist"] = {"status": "FAIL", "error": str(e)}
622
+
623
+ # Summary
624
+ n_pass = sum(1 for c in checks.values() if c.get("status") == "PASS")
625
+ n_fail = sum(1 for c in checks.values() if c.get("status") == "FAIL")
626
+ return {
627
+ "checks": checks,
628
+ "n_pass": n_pass,
629
+ "n_fail": n_fail,
630
+ "all_pass": n_fail == 0,
631
+ }
632
+
633
+
634
+ # ============================================================================
635
+ # 9. PHASE 1 — CONHECIMENTO (streaming 8 datasets, sem punição)
636
+ # ============================================================================
637
+ def run_fase_conhecimento(
638
+ kls: KohonenLearningSystemV2,
639
+ hf_token: Optional[str],
640
+ ) -> Dict[str, Any]:
641
+ """Fase 1 — CONHECIMENTO: streaming 8 datasets, sem punição.
642
+
643
+ User requirement: "streaming CONHECIMENTO de 100 em 100 samples nesta
644
+ sequência [8 datasets]" + "meta mínima 8000 samples ou mais para
645
+ CONHECIMENTO"
646
+
647
+ Para cada dataset:
648
+ - Stream em chunks de 100 samples.
649
+ - process_batch_v2(enable_punishment=False) — apenas acumula conhecimento.
650
+ - Pausas inter-batch e inter-dataset.
651
+
652
+ Returns:
653
+ Dict com métricas da fase CONHECIMENTO.
654
+ """
655
+ logger.info("\n" + "=" * 80)
656
+ logger.info("[V6.5-V2] FASE 1 — CONHECIMENTO (sem punição)")
657
+ logger.info("=" * 80)
658
+ logger.info(f" Datasets: {len(CONHECIMENTO_DATASETS)}")
659
+ logger.info(f" Max samples/dataset: {MAX_SAMPLES_PER_DATASET_CONHECIMENTO}")
660
+ logger.info(f" Meta mínima: {META_MINIMA_CONHECIMENTO}")
661
+ logger.info(f" Stream batch size: {STREAM_BATCH_SIZE}")
662
+ logger.info("=" * 80 + "\n")
663
+
664
+ step = 0
665
+ t_start = time.time()
666
+ samples_per_dataset: Dict[str, int] = {ds: 0 for ds in CONHECIMENTO_DATASETS}
667
+ streaming_failures: Dict[str, int] = {ds: 0 for ds in CONHECIMENTO_DATASETS}
668
+ storage_critical_stopped = False
669
+ chunk_idx_global = 0
670
+ accuracies_log: List[Dict[str, Any]] = []
671
+ attention_log: List[Dict[str, Any]] = []
672
+
673
+ for ds_idx, dataset_name in enumerate(CONHECIMENTO_DATASETS):
674
+ if storage_critical_stopped:
675
+ break
676
+ total_so_far = sum(samples_per_dataset.values())
677
+ if total_so_far >= META_MINIMA_CONHECIMENTO:
678
+ logger.info(
679
+ f"[V6.5-V2] Meta CONHECIMENTO atingida ({total_so_far} ≥ "
680
+ f"{META_MINIMA_CONHECIMENTO}). Parando Fase 1."
681
+ )
682
+ break
683
+ logger.info(
684
+ f"\n[V6.5-V2] {'='*40} DATASET {ds_idx+1}/{len(CONHECIMENTO_DATASETS)}: "
685
+ f"{dataset_name} {'='*40}"
686
+ )
687
+ logger.info(
688
+ f"[V6.5-V2] Streaming {dataset_name} in chunks of {STREAM_BATCH_SIZE}..."
689
+ )
690
+
691
+ try:
692
+ chunk_iter = stream_dataset_in_chunks(
693
+ dataset_name=dataset_name,
694
+ chunk_size=STREAM_BATCH_SIZE,
695
+ max_total=MAX_SAMPLES_PER_DATASET_CONHECIMENTO,
696
+ hf_token=hf_token,
697
+ timeout_per_chunk=90,
698
+ )
699
+ for chunk_samples in chunk_iter:
700
+ if storage_critical_stopped:
701
+ break
702
+ total_so_far = sum(samples_per_dataset.values())
703
+ if total_so_far >= META_MINIMA_CONHECIMENTO:
704
+ logger.info(
705
+ f"[V6.5-V2] Meta CONHECIMENTO atingida durante {dataset_name}."
706
+ )
707
+ break
708
+ chunk_idx_global += 1
709
+ if not chunk_samples:
710
+ streaming_failures[dataset_name] += 1
711
+ continue
712
+ samples_per_dataset[dataset_name] += len(chunk_samples)
713
+ labels = [make_label(s, dataset_name) for s in chunk_samples]
714
+ logger.info(
715
+ f"[V6.5-V2] Processing chunk {chunk_idx_global} "
716
+ f"({len(chunk_samples)} samples) from {dataset_name}"
717
+ )
718
+
719
+ # Processa em batches COM PAUSAS
720
+ for batch_start in range(0, len(chunk_samples), BATCH_SIZE):
721
+ try:
722
+ if step > 0 and step % STORAGE_CHECK_INTERVAL_STEPS == 0:
723
+ disk_pct = get_disk_usage_pct()
724
+ rss_mb = get_process_rss_mb()
725
+ cg_limit = get_cgroup_memory_limit_mb()
726
+ if cg_limit is not None:
727
+ mem_pct = (rss_mb / cg_limit) * 100.0
728
+ logger.info(
729
+ f"[V6.5-V2] MEM: RSS={rss_mb:.0f}MB / "
730
+ f"cg_limit={cg_limit:.0f}MB ({mem_pct:.1f}%)"
731
+ )
732
+ if mem_pct > CGROUP_MEM_CRITICAL_PCT:
733
+ logger.error(
734
+ f"[V6.5-V2] MEM CRITICAL: RSS={rss_mb:.0f}MB "
735
+ f"({mem_pct:.1f}% of {cg_limit:.0f}MB). "
736
+ f"STOPPING CONHECIMENTO (graceful)."
737
+ )
738
+ total_now = sum(samples_per_dataset.values())
739
+ save_model_states_for_evaluation(
740
+ kls=kls,
741
+ reason=f"mem_critical_conhecimento_{mem_pct:.1f}pct",
742
+ step=step,
743
+ total_samples=total_now,
744
+ )
745
+ storage_critical_stopped = True
746
+ break
747
+ if disk_pct > STORAGE_CRITICAL_PCT:
748
+ logger.error(
749
+ f"[V6.5-V2] STORAGE CRITICAL: disk={disk_pct:.1f}% "
750
+ f"> threshold={STORAGE_CRITICAL_PCT}%. "
751
+ f"STOPPING CONHECIMENTO."
752
+ )
753
+ total_now = sum(samples_per_dataset.values())
754
+ save_model_states_for_evaluation(
755
+ kls=kls,
756
+ reason=f"storage_critical_conhecimento_disk_{disk_pct:.1f}pct",
757
+ step=step,
758
+ total_samples=total_now,
759
+ )
760
+ storage_critical_stopped = True
761
+ break
762
+
763
+ batch_sents = chunk_samples[batch_start: batch_start + BATCH_SIZE]
764
+ batch_labels = labels[batch_start: batch_start + BATCH_SIZE]
765
+ try:
766
+ # FASE 1: enable_punishment=False (apenas CONHECIMENTO)
767
+ result = kls.process_batch_v2(
768
+ batch_sents,
769
+ batch_labels,
770
+ label_strings=DATASET_LABEL_STRINGS.get(dataset_name),
771
+ dataset_name=dataset_name,
772
+ enable_punishment=False,
773
+ )
774
+ except Exception as e:
775
+ logger.error(f"[V6.5-V2] process_batch_v2 error: {e}")
776
+ traceback.print_exc()
777
+ continue
778
+
779
+ # Métricas
780
+ acc = kls.evaluate_classification()
781
+ accuracies_log.append({
782
+ "step": step,
783
+ "dataset": dataset_name,
784
+ "chunk_idx": chunk_idx_global,
785
+ "batch_size": len(batch_sents),
786
+ "accuracy": float(acc),
787
+ "phase": "CONHECIMENTO",
788
+ "buffer_size": int(len(kls.buffer_4d)),
789
+ "training_ready": bool(kls.training_ready),
790
+ "elapsed_ms": float(result.get("elapsed_ms", 0.0)),
791
+ })
792
+
793
+ # Attention log
794
+ attn_metrics = kls.get_attention_metrics()
795
+ if attn_metrics.get("n_calls", 0) > len(attention_log) * 16:
796
+ attention_log.append({
797
+ "step": step,
798
+ "dataset": dataset_name,
799
+ "n_calls": int(attn_metrics.get("n_calls", 0)),
800
+ "n_errors": int(attn_metrics.get("n_errors", 0)),
801
+ "last_attn_activated": bool(attn_metrics.get("last_attn_activated", False)),
802
+ "logic_functional": bool(attn_metrics.get("logic_functional", False)),
803
+ })
804
+
805
+ step += 1
806
+ time.sleep(INTER_BATCH_PAUSE_S)
807
+ except Exception as e:
808
+ logger.error(f"[V6.5-V2] Batch error: {e}")
809
+ traceback.print_exc()
810
+ continue
811
+
812
+ time.sleep(INTER_STREAM_BATCH_PAUSE_S)
813
+ # V2-dynamic-memory — Buffer sliding window: trunca para os
814
+ # últimos MAX_BUFFER_SIZE amostras após cada chunk.
815
+ # Os pesos do SOM já capturam o conhecimento acumulado,
816
+ # então o buffer só precisa conter amostras recentes.
817
+ if len(kls.buffer_4d) > MAX_BUFFER_SIZE:
818
+ overflow = len(kls.buffer_4d) - MAX_BUFFER_SIZE
819
+ del kls.buffer_4d[:overflow]
820
+ del kls.buffer_labels[:overflow]
821
+ logger.info(
822
+ f"[V6.5-V2] Buffer trimmed: -{overflow} → "
823
+ f"{len(kls.buffer_4d)} samples (cap={MAX_BUFFER_SIZE})"
824
+ )
825
+ # Aggressive memory cleanup between chunks
826
+ if chunk_idx_global % 2 == 0:
827
+ aggressive_memory_cleanup()
828
+ except Exception as e:
829
+ logger.error(f"[V6.5-V2] Dataset {dataset_name} failed: {e}")
830
+ traceback.print_exc()
831
+ streaming_failures[dataset_name] += 1
832
+
833
+ time.sleep(INTER_DATASET_PAUSE_S)
834
+
835
+ t_elapsed = time.time() - t_start
836
+ total_samples = sum(samples_per_dataset.values())
837
+
838
+ logger.info(f"\n[V6.5-V2] FASE 1 (CONHECIMENTO) concluída:")
839
+ logger.info(f" Total samples: {total_samples}")
840
+ logger.info(f" Meta atingida: {total_samples >= META_MINIMA_CONHECIMENTO}")
841
+ logger.info(f" Tempo total: {t_elapsed:.1f}s")
842
+ logger.info(f" Storage critical stopped: {storage_critical_stopped}")
843
+
844
+ return {
845
+ "phase": "CONHECIMENTO",
846
+ "total_samples": int(total_samples),
847
+ "meta_minima": int(META_MINIMA_CONHECIMENTO),
848
+ "meta_atingida": bool(total_samples >= META_MINIMA_CONHECIMENTO),
849
+ "samples_per_dataset": samples_per_dataset,
850
+ "streaming_failures": streaming_failures,
851
+ "storage_critical_stopped": bool(storage_critical_stopped),
852
+ "elapsed_s": float(t_elapsed),
853
+ "n_steps": int(step),
854
+ "n_chunks": int(chunk_idx_global),
855
+ "accuracies_log": accuracies_log[-50:], # últimos 50
856
+ "attention_log": attention_log[-20:],
857
+ "final_state": kls.get_v2_metrics(),
858
+ }
859
+
860
+
861
+ # ============================================================================
862
+ # 10. PHASE 2 — TREINAMENTO COM PUNIÇÃO (16 hipóteses × 3 tentativas)
863
+ # ============================================================================
864
+ def run_fase_punicão(
865
+ kls: KohonenLearningSystemV2,
866
+ hf_token: Optional[str],
867
+ ) -> Dict[str, Any]:
868
+ """Fase 2 — TREINAMENTO COM PUNIÇÃO: streaming 500 samples + V2 protocol.
869
+
870
+ User requirement: "dataset para TREINAMENTO COM PUNIÇÃO ATIVA
871
+ 'BrunoN-Dev/corpus-ptbr-v1'" + "meta mínima 500 para TREINAMENTO COM
872
+ PUNIÇÃO" + "Cada evento de erro (punição) dispara 3 tentativas de ajuste.
873
+ Em cada tentativa, 16 geradores paralelos de hipóteses produzem candidatos
874
+ a delta. O melhor delta é aplicado ao MAPA-SOM. Após a aplicação,
875
+ consolidação via EWC."
876
+
877
+ Returns:
878
+ Dict com métricas da fase TREINAMENTO COM PUNIÇÃO.
879
+ """
880
+ logger.info("\n" + "=" * 80)
881
+ logger.info("[V6.5-V2] FASE 2 — TREINAMENTO COM PUNIÇÃO (16 hipóteses × 3 tentativas)")
882
+ logger.info("=" * 80)
883
+ logger.info(f" Dataset: {PUNICAO_DATASET}")
884
+ logger.info(f" Max samples: {MAX_SAMPLES_PUNICAO}")
885
+ logger.info(f" Meta mínima: {META_MINIMA_PUNICAO}")
886
+ logger.info(f" n_hypotheses: {N_HYPOTHESES}")
887
+ logger.info(f" n_trials: {N_TRIALS}")
888
+ logger.info(f" hyp_train_steps: {HYP_TRAIN_STEPS}")
889
+ logger.info("=" * 80 + "\n")
890
+
891
+ step = 0
892
+ t_start = time.time()
893
+ samples_processed = 0
894
+ storage_critical_stopped = False
895
+ chunk_idx_global = 0
896
+ punishment_log: List[Dict[str, Any]] = []
897
+ hypotheses_log: List[Dict[str, Any]] = []
898
+ accuracies_log: List[Dict[str, Any]] = []
899
+ delta_applications_log: List[Dict[str, Any]] = []
900
+
901
+ try:
902
+ chunk_iter = stream_dataset_in_chunks(
903
+ dataset_name=PUNICAO_DATASET,
904
+ chunk_size=STREAM_BATCH_SIZE,
905
+ max_total=MAX_SAMPLES_PUNICAO,
906
+ hf_token=hf_token,
907
+ timeout_per_chunk=90,
908
+ )
909
+ for chunk_samples in chunk_iter:
910
+ if storage_critical_stopped:
911
+ break
912
+ if samples_processed >= META_MINIMA_PUNICAO:
913
+ logger.info(
914
+ f"[V6.5-V2] Meta PUNIÇÃO atingida ({samples_processed} ≥ "
915
+ f"{META_MINIMA_PUNICAO})."
916
+ )
917
+ break
918
+ chunk_idx_global += 1
919
+ if not chunk_samples:
920
+ continue
921
+ samples_processed += len(chunk_samples)
922
+ labels = [make_label(s, PUNICAO_DATASET) for s in chunk_samples]
923
+ logger.info(
924
+ f"[V6.5-V2] PUNIÇÃO chunk {chunk_idx_global} "
925
+ f"({len(chunk_samples)} samples) from {PUNICAO_DATASET}"
926
+ )
927
+
928
+ for batch_start in range(0, len(chunk_samples), BATCH_SIZE):
929
+ try:
930
+ if step > 0 and step % STORAGE_CHECK_INTERVAL_STEPS == 0:
931
+ disk_pct = get_disk_usage_pct()
932
+ if disk_pct > STORAGE_CRITICAL_PCT:
933
+ logger.error(
934
+ f"[V6.5-V2] STORAGE CRITICAL: disk={disk_pct:.1f}%. "
935
+ f"STOPPING PUNIÇÃO."
936
+ )
937
+ save_model_states_for_evaluation(
938
+ kls=kls,
939
+ reason=f"storage_critical_punicão_disk_{disk_pct:.1f}pct",
940
+ step=step,
941
+ total_samples=samples_processed,
942
+ )
943
+ storage_critical_stopped = True
944
+ break
945
+
946
+ batch_sents = chunk_samples[batch_start: batch_start + BATCH_SIZE]
947
+ batch_labels = labels[batch_start: batch_start + BATCH_SIZE]
948
+ try:
949
+ # FASE 2: enable_punishment=True (V2 protocol)
950
+ result = kls.process_batch_v2(
951
+ batch_sents,
952
+ batch_labels,
953
+ label_strings=DATASET_LABEL_STRINGS.get(PUNICAO_DATASET),
954
+ dataset_name=PUNICAO_DATASET,
955
+ enable_punishment=True,
956
+ )
957
+ except Exception as e:
958
+ logger.error(f"[V6.5-V2] process_batch_v2 error: {e}")
959
+ traceback.print_exc()
960
+ continue
961
+
962
+ # Log punishment events
963
+ action = result.get("action", "none")
964
+ if action != "none" and action != "success":
965
+ punishment_log.append({
966
+ "step": step,
967
+ "action": action,
968
+ "accuracy": float(result.get("accuracy", 0.0)),
969
+ "punishment_count": int(kls.punishment_count),
970
+ "cycle_completed": bool(result.get("cycle_completed", False)),
971
+ })
972
+ # Log hypotheses training
973
+ if "hypotheses_training" in result:
974
+ hyp_info = result["hypotheses_training"]
975
+ hypotheses_log.append({
976
+ "step": step,
977
+ "loss_initial": float(hyp_info.get("loss_initial", 0.0)),
978
+ "loss_final": float(hyp_info.get("loss_final", 0.0)),
979
+ "delta_scale": float(hyp_info.get("delta_scale_final", 0.0)),
980
+ "elapsed_ms": float(hyp_info.get("elapsed_ms", 0.0)),
981
+ })
982
+ # Log delta applications
983
+ if "delta_application" in result:
984
+ apply_info = result["delta_application"]
985
+ delta_applications_log.append({
986
+ "step": step,
987
+ "acc_before": float(apply_info.get("acc_before", 0.0)),
988
+ "acc_after": float(apply_info.get("acc_after", 0.0)),
989
+ "best_acc_during_selection": float(apply_info.get("best_acc_during_selection", 0.0)),
990
+ "delta_norm": float(apply_info.get("delta_norm", 0.0)),
991
+ "ewc_reference_set": bool(apply_info.get("ewc_reference_set", False)),
992
+ "elapsed_ms": float(apply_info.get("elapsed_ms", 0.0)),
993
+ })
994
+
995
+ # Accuracy log
996
+ acc = kls.evaluate_classification()
997
+ accuracies_log.append({
998
+ "step": step,
999
+ "accuracy": float(acc),
1000
+ "phase": "PUNICAO",
1001
+ "action": action,
1002
+ "buffer_size": int(len(kls.buffer_4d)),
1003
+ "punishment_count": int(kls.punishment_count),
1004
+ "success_count": int(kls.success_count),
1005
+ "ewc_reference_set": bool(kls.som.old_weights_w is not None),
1006
+ })
1007
+
1008
+ step += 1
1009
+ time.sleep(INTER_BATCH_PAUSE_S)
1010
+ except Exception as e:
1011
+ logger.error(f"[V6.5-V2] Batch error in PUNIÇÃO: {e}")
1012
+ traceback.print_exc()
1013
+ continue
1014
+
1015
+ time.sleep(INTER_STREAM_BATCH_PAUSE_S)
1016
+ # V2-dynamic-memory — Buffer sliding window na PUNIÇÃO também
1017
+ if len(kls.buffer_4d) > MAX_BUFFER_SIZE:
1018
+ overflow = len(kls.buffer_4d) - MAX_BUFFER_SIZE
1019
+ del kls.buffer_4d[:overflow]
1020
+ del kls.buffer_labels[:overflow]
1021
+ logger.info(
1022
+ f"[V6.5-V2] PUNIÇÃO buffer trimmed: -{overflow} → "
1023
+ f"{len(kls.buffer_4d)} samples"
1024
+ )
1025
+ if chunk_idx_global % 2 == 0:
1026
+ aggressive_memory_cleanup()
1027
+ except Exception as e:
1028
+ logger.error(f"[V6.5-V2] PUNIÇÃO dataset failed: {e}")
1029
+ traceback.print_exc()
1030
+
1031
+ t_elapsed = time.time() - t_start
1032
+
1033
+ logger.info(f"\n[V6.5-V2] FASE 2 (PUNIÇÃO) concluída:")
1034
+ logger.info(f" Total samples: {samples_processed}")
1035
+ logger.info(f" Meta atingida: {samples_processed >= META_MINIMA_PUNICAO}")
1036
+ logger.info(f" Tempo total: {t_elapsed:.1f}s")
1037
+ logger.info(f" Punishment events: {len(punishment_log)}")
1038
+ logger.info(f" Hypotheses trainings: {len(hypotheses_log)}")
1039
+ logger.info(f" Delta applications: {len(delta_applications_log)}")
1040
+
1041
+ return {
1042
+ "phase": "TREINAMENTO_COM_PUNICAO",
1043
+ "dataset": PUNICAO_DATASET,
1044
+ "total_samples": int(samples_processed),
1045
+ "meta_minima": int(META_MINIMA_PUNICAO),
1046
+ "meta_atingida": bool(samples_processed >= META_MINIMA_PUNICAO),
1047
+ "storage_critical_stopped": bool(storage_critical_stopped),
1048
+ "elapsed_s": float(t_elapsed),
1049
+ "n_steps": int(step),
1050
+ "n_chunks": int(chunk_idx_global),
1051
+ "punishment_events": punishment_log,
1052
+ "hypotheses_trainings": hypotheses_log,
1053
+ "delta_applications": delta_applications_log,
1054
+ "accuracies_log": accuracies_log[-50:],
1055
+ "final_v2_state": kls.get_v2_metrics(),
1056
+ }
1057
+
1058
+
1059
+ # ============================================================================
1060
+ # 11. Evaluate attention (ativo e logicamente funcional)
1061
+ # ============================================================================
1062
+ def evaluate_attention(kls: KohonenLearningSystemV2) -> Dict[str, Any]:
1063
+ """V6.5-V2 — Avalia se o mecanismo de atenção está ativo e funcional."""
1064
+ metrics_snapshot = kls.get_attention_metrics()
1065
+ return {
1066
+ "evaluation": "attention_v65_v2",
1067
+ "user_requirement": "verificar se o mecanismo de atenção está ativo e acessado logicamente funcional",
1068
+ "metrics": metrics_snapshot,
1069
+ "active": bool(metrics_snapshot.get("active", False)),
1070
+ "logic_functional": bool(metrics_snapshot.get("logic_functional", False)),
1071
+ "n_calls": int(metrics_snapshot.get("n_calls", 0)),
1072
+ "n_errors": int(metrics_snapshot.get("n_errors", 0)),
1073
+ "n_heads": int(metrics_snapshot.get("n_heads", 0)),
1074
+ "assessment": "PASS" if metrics_snapshot.get("logic_functional") else "FAIL",
1075
+ }
1076
+
1077
+
1078
+ # ============================================================================
1079
+ # 12. Evaluate predict fix (rótulos dinâmicos, não hardcoded)
1080
+ # ============================================================================
1081
+ def evaluate_predict_fix(kls: KohonenLearningSystemV2) -> Dict[str, Any]:
1082
+ """V6.5-V2 — Avalia que predict() NÃO retorna mais 'gato'/'cachorro' fixos."""
1083
+ test_queries = [
1084
+ "o gato dorme na cama",
1085
+ "calcule dois mais dois",
1086
+ "qual é a capital do brasil",
1087
+ "explique o que é uma rede neural",
1088
+ "olá como você está",
1089
+ "traduza hello para portugues",
1090
+ ]
1091
+ results = []
1092
+ n_returns_gato = 0
1093
+ n_returns_cachorro = 0
1094
+ n_returns_registry_label = 0
1095
+ n_returns_default_label = 0
1096
+
1097
+ registry_state = kls.get_label_registry_state()
1098
+ all_registered_labels = set()
1099
+ for ds_name, mapping in registry_state["datasets"].items():
1100
+ for label_str in mapping.values():
1101
+ all_registered_labels.add(label_str)
1102
+ default_labels = set(registry_state["default_label_strings"].values())
1103
+
1104
+ for q in test_queries:
1105
+ try:
1106
+ pred = kls.predict(q)
1107
+ except Exception as e:
1108
+ pred = f"<error: {e}>"
1109
+ try:
1110
+ pred_proba, prob = kls.predict_proba(q)
1111
+ except Exception as e:
1112
+ pred_proba, prob = f"<error: {e}>", -1.0
1113
+
1114
+ is_gato = (pred == "gato")
1115
+ is_cachorro = (pred == "cachorro")
1116
+ is_registry = pred in all_registered_labels
1117
+ is_default = pred in default_labels
1118
+
1119
+ if is_gato: n_returns_gato += 1
1120
+ if is_cachorro: n_returns_cachorro += 1
1121
+ if is_registry: n_returns_registry_label += 1
1122
+ if is_default: n_returns_default_label += 1
1123
+
1124
+ results.append({
1125
+ "query": q,
1126
+ "prediction": str(pred),
1127
+ "probability": float(prob) if isinstance(prob, (int, float)) else -1.0,
1128
+ "is_gato_hardcoded": bool(is_gato),
1129
+ "is_cachorro_hardcoded": bool(is_cachorro),
1130
+ "is_registry_label": bool(is_registry),
1131
+ "is_default_label": bool(is_default),
1132
+ })
1133
+
1134
+ # Per-dataset check
1135
+ per_dataset_results = []
1136
+ for ds_name, mapping in registry_state["datasets"].items():
1137
+ try:
1138
+ pred = kls.predict("teste de predição", dataset_name=ds_name)
1139
+ valid = pred in set(mapping.values())
1140
+ except Exception as e:
1141
+ pred = f"<error: {e}>"
1142
+ valid = False
1143
+ per_dataset_results.append({
1144
+ "dataset": ds_name,
1145
+ "expected_labels": list(mapping.values()),
1146
+ "prediction": str(pred),
1147
+ "valid_for_dataset": bool(valid),
1148
+ })
1149
+
1150
+ return {
1151
+ "evaluation": "predict_fix_v65_v2",
1152
+ "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",
1153
+ "n_test_queries": len(test_queries),
1154
+ "results": results,
1155
+ "per_dataset_results": per_dataset_results,
1156
+ "summary": {
1157
+ "n_returns_gato": int(n_returns_gato),
1158
+ "n_returns_cachorro": int(n_returns_cachorro),
1159
+ "n_returns_registry_label": int(n_returns_registry_label),
1160
+ "n_returns_default_label": int(n_returns_default_label),
1161
+ "hardcoded_bug_present": bool(n_returns_gato > 0 or n_returns_cachorro > 0),
1162
+ "predict_fix_verified": bool(n_returns_gato == 0 and n_returns_cachorro == 0),
1163
+ },
1164
+ "quality_assessment": {
1165
+ "fix_status": "PASS" if (n_returns_gato == 0 and n_returns_cachorro == 0) else "FAIL",
1166
+ "note": "predict() não retorna mais 'gato'/'cachorro' fixos — usa label_registry dinâmico.",
1167
+ },
1168
+ }
1169
+
1170
+
1171
+ # ============================================================================
1172
+ # 13. Launch user questions WITHOUT help (3 perguntas, sem auxílio)
1173
+ # ============================================================================
1174
+ def launch_user_questions_without_help(
1175
+ kls: KohonenLearningSystemV2,
1176
+ ) -> Dict[str, Any]:
1177
+ """V6.5-V2 — Envia as 3 perguntas específicas SEM nenhum contexto.
1178
+
1179
+ User requirement: "não ajudar o modelo em respostas e lançar perguntas:
1180
+ 'Luva de Pedreiro Távila' e 'Lula reserva valor' e
1181
+ 'Amazonas força-tarefa vítimas'"
1182
+
1183
+ IMPORTANTE: As perguntas são enviadas EXATAMENTE como o usuário as escreveu,
1184
+ sem nenhum prompt adicional, sem contexto, sem instrução de formato,
1185
+ sem system prompt, sem few-shot examples.
1186
+ """
1187
+ user_questions = [
1188
+ "Luva de Pedreiro Távila",
1189
+ "Lula reserva valor",
1190
+ "Amazonas força-tarefa vítimas",
1191
+ ]
1192
+ results = []
1193
+ for q in user_questions:
1194
+ t_start = time.time()
1195
+ try:
1196
+ som_pred = kls.predict(q)
1197
+ except Exception as e:
1198
+ som_pred = f"<predict_error: {e}>"
1199
+ try:
1200
+ reasoning_text = kls.reason_sync(q)
1201
+ except Exception as e:
1202
+ reasoning_text = f"<reasoning_error: {e}>"
1203
+ latency_ms = (time.time() - t_start) * 1000.0
1204
+ think_match = re.search(r"<think>(.*?)</think>", reasoning_text, re.DOTALL)
1205
+ plan_match = re.search(r"<plan>(.*?)</plan>", reasoning_text, re.DOTALL)
1206
+ answer_match = re.search(r"<answer>(.*?)</answer>", reasoning_text, re.DOTALL)
1207
+ decompose_match = re.search(r"<decompose>(.*?)</decompose>", reasoning_text, re.DOTALL)
1208
+ results.append({
1209
+ "query": q,
1210
+ "query_was_modified": False,
1211
+ "context_provided": False,
1212
+ "system_prompt_used": False,
1213
+ "few_shot_examples": False,
1214
+ "som_prediction": str(som_pred),
1215
+ "reasoning_length": int(len(reasoning_text)),
1216
+ "has_think": bool(think_match),
1217
+ "has_plan": bool(plan_match),
1218
+ "has_answer": bool(answer_match),
1219
+ "has_decompose": bool(decompose_match),
1220
+ "think_preview": (
1221
+ think_match.group(1).strip()[:200] + ("..." if len(think_match.group(1)) > 200 else "")
1222
+ ) if think_match else "",
1223
+ "answer_preview": (
1224
+ answer_match.group(1).strip()[:200] + ("..." if len(answer_match.group(1)) > 200 else "")
1225
+ ) if answer_match else "",
1226
+ "raw_response_preview": reasoning_text[:500] + ("..." if len(reasoning_text) > 500 else ""),
1227
+ "n_tags": sum(1 for tag in ["<think>", "<plan>", "<decompose>", "<answer>"] if tag in reasoning_text),
1228
+ "latency_ms": float(latency_ms),
1229
+ })
1230
+ n_answer = sum(1 for r in results if r["has_answer"])
1231
+ n_think = sum(1 for r in results if r["has_think"])
1232
+ return {
1233
+ "evaluation": "user_questions_without_help_v65_v2",
1234
+ "user_requirement": "não ajudar o modelo em respostas e lançar perguntas",
1235
+ "questions_sent_verbatim": True,
1236
+ "no_context_added": True,
1237
+ "no_system_prompt": True,
1238
+ "no_few_shot": True,
1239
+ "n_questions": len(user_questions),
1240
+ "questions": user_questions,
1241
+ "results": results,
1242
+ "summary": {
1243
+ "n_with_answer": n_answer,
1244
+ "n_with_think": n_think,
1245
+ "answer_rate": float(n_answer / max(1, len(results))),
1246
+ "think_rate": float(n_think / max(1, len(results))),
1247
+ "avg_latency_ms": float(sum(r["latency_ms"] for r in results) / max(1, len(results))),
1248
+ "avg_reasoning_length": float(sum(r["reasoning_length"] for r in results) / max(1, len(results))),
1249
+ },
1250
+ "quality_assessment": {
1251
+ "model_not_helped": True,
1252
+ "note": "As 3 perguntas foram enviadas verbatim, sem system prompt, sem few-shot, sem contexto adicional.",
1253
+ },
1254
+ }
1255
+
1256
+
1257
+ # ============================================================================
1258
+ # 13.5 HF Batch Upload — envia scripts+estado+modelo ao HF em lote
1259
+ # ============================================================================
1260
+ HF_REPO_ID = "PowerMachine/BiGRU_T_version"
1261
+
1262
+
1263
+ def upload_to_hf_batch(
1264
+ hf_token: str,
1265
+ files_to_upload: List[Path],
1266
+ repo_id: str = HF_REPO_ID,
1267
+ repo_type: str = "model",
1268
+ ) -> Dict[str, Any]:
1269
+ """V6.5-V2-dynamic — Envia arquivos ao HF em LOTE (commit único).
1270
+
1271
+ User requirement: "atualizações para o HF devem ser feitas em lote" +
1272
+ "após concluir enviar scripts e arquivos e estado do modelo testados e
1273
+ aprovados sobrescrevendo os antigos desatualizados".
1274
+
1275
+ Args:
1276
+ hf_token: token HF (será apagado após uso).
1277
+ files_to_upload: lista de paths locais a enviar.
1278
+ repo_id: repositório HF destino.
1279
+ repo_type: 'model', 'dataset' ou 'space'.
1280
+
1281
+ Returns:
1282
+ Dict com status de cada upload e URL do commit.
1283
+ """
1284
+ if not hf_token:
1285
+ return {"uploaded": False, "reason": "no_hf_token"}
1286
+
1287
+ try:
1288
+ from huggingface_hub import HfApi, whoami
1289
+ except ImportError as e:
1290
+ logger.error(f"[V6.5-V2] huggingface_hub not installed: {e}")
1291
+ return {"uploaded": False, "reason": f"import_error: {e}"}
1292
+
1293
+ api = HfApi(token=hf_token)
1294
+ try:
1295
+ user_info = whoami(token=hf_token)
1296
+ logger.info(f"[V6.5-V2] HF authenticated as: {user_info.get('name', 'unknown')}")
1297
+ except Exception as e:
1298
+ logger.error(f"[V6.5-V2] HF auth failed: {e}")
1299
+ return {"uploaded": False, "reason": f"auth_failed: {e}"}
1300
+
1301
+ # Garante que o repo existe
1302
+ try:
1303
+ api.repo_info(repo_id=repo_id, repo_type=repo_type)
1304
+ except Exception:
1305
+ try:
1306
+ api.create_repo(repo_id=repo_id, repo_type=repo_type, exist_ok=True)
1307
+ logger.info(f"[V6.5-V2] Created HF repo: {repo_id}")
1308
+ except Exception as e:
1309
+ logger.warning(f"[V6.5-V2] Could not create repo {repo_id}: {e}")
1310
+
1311
+ # Filtra arquivos existentes
1312
+ upload_plan: List[Dict[str, Any]] = []
1313
+ for src in files_to_upload:
1314
+ if not src.exists():
1315
+ logger.warning(f"[V6.5-V2] Skipping non-existent file: {src}")
1316
+ continue
1317
+ # Caminho no repo: mantém apenas o nome do arquivo (sem dirs locais)
1318
+ path_in_repo = src.name
1319
+ upload_plan.append({
1320
+ "local": str(src),
1321
+ "path_in_repo": path_in_repo,
1322
+ "size_mb": float(src.stat().st_size / 1e6),
1323
+ })
1324
+
1325
+ if not upload_plan:
1326
+ return {"uploaded": False, "reason": "no_files_to_upload"}
1327
+
1328
+ logger.info(
1329
+ f"[V6.5-V2] Uploading {len(upload_plan)} files to HF "
1330
+ f"repo={repo_id} in BATCH (single commit):"
1331
+ )
1332
+ for item in upload_plan:
1333
+ logger.info(f" - {item['local']} → {item['path_in_repo']} "
1334
+ f"({item['size_mb']:.2f}MB)")
1335
+
1336
+ # Upload em lote (commit único): usa upload_folder com todos os arquivos
1337
+ # numa pasta temporária — ou, mais simples, upload_file individual mas
1338
+ # em sequência rápida. Para commit único verdadeiro, usaremos create_commit.
1339
+ results: List[Dict[str, Any]] = []
1340
+ try:
1341
+ # Método 1: create_commit com múltiplos operations (commit único)
1342
+ from huggingface_hub import CommitOperationAdd
1343
+ operations = []
1344
+ for item in upload_plan:
1345
+ operations.append(CommitOperationAdd(
1346
+ path_in_repo=item["path_in_repo"],
1347
+ path_or_fileobj=item["local"],
1348
+ ))
1349
+ commit_info = api.create_commit(
1350
+ repo_id=repo_id,
1351
+ repo_type=repo_type,
1352
+ operations=operations,
1353
+ commit_message=(
1354
+ f"V6.5-V2-dynamic: upload batch (scripts + state + model) "
1355
+ f"[{len(operations)} files]"
1356
+ ),
1357
+ )
1358
+ logger.info(f"[V6.5-V2] Batch commit created: {commit_info}")
1359
+ for item in upload_plan:
1360
+ results.append({
1361
+ "file": item["path_in_repo"],
1362
+ "uploaded": True,
1363
+ "size_mb": item["size_mb"],
1364
+ })
1365
+ return {
1366
+ "uploaded": True,
1367
+ "n_files": len(results),
1368
+ "commit_url": str(commit_info.commit_url) if hasattr(commit_info, "commit_url") else str(commit_info),
1369
+ "results": results,
1370
+ }
1371
+ except Exception as e:
1372
+ logger.error(f"[V6.5-V2] Batch commit failed: {e}")
1373
+ traceback.print_exc()
1374
+
1375
+ # Método 2 (fallback): upload individual
1376
+ logger.info("[V6.5-V2] Falling back to individual uploads...")
1377
+ for item in upload_plan:
1378
+ try:
1379
+ api.upload_file(
1380
+ path_or_fileobj=item["local"],
1381
+ path_in_repo=item["path_in_repo"],
1382
+ repo_id=repo_id,
1383
+ repo_type=repo_type,
1384
+ )
1385
+ results.append({
1386
+ "file": item["path_in_repo"],
1387
+ "uploaded": True,
1388
+ "size_mb": item["size_mb"],
1389
+ })
1390
+ logger.info(f" ✓ {item['path_in_repo']} uploaded")
1391
+ except Exception as e:
1392
+ results.append({
1393
+ "file": item["path_in_repo"],
1394
+ "uploaded": False,
1395
+ "error": str(e)[:200],
1396
+ })
1397
+ logger.error(f" ✗ {item['path_in_repo']} failed: {e}")
1398
+
1399
+ return {
1400
+ "uploaded": any(r.get("uploaded") for r in results),
1401
+ "n_files": len(results),
1402
+ "n_uploaded": sum(1 for r in results if r.get("uploaded")),
1403
+ "results": results,
1404
+ }
1405
+
1406
+
1407
+ def scrub_hf_token_from_scripts(scripts_dir: Path) -> Dict[str, Any]:
1408
+ """V6.5-V2-dynamic — Apaga HF_TOKEN de todos os scripts no diretório.
1409
+
1410
+ User requirement: "HF_TOKEN deve ser apagada dos scripts enviados ao HF
1411
+ após uso".
1412
+
1413
+ Usa regex para detectar qualquer string que pareça um token HF
1414
+ (hf_<alphanumeric>{32,}) e substitui por '<HF_TOKEN_REMOVED>'.
1415
+ """
1416
+ pattern = re.compile(r'hf_[A-Za-z0-9]{32,}')
1417
+ n_files_scanned = 0
1418
+ n_files_modified = 0
1419
+ n_tokens_removed = 0
1420
+ for py_file in scripts_dir.rglob("*.py"):
1421
+ n_files_scanned += 1
1422
+ try:
1423
+ content = py_file.read_text(encoding="utf-8")
1424
+ matches = pattern.findall(content)
1425
+ if matches:
1426
+ new_content = pattern.sub("<HF_TOKEN_REMOVED>", content)
1427
+ py_file.write_text(new_content, encoding="utf-8")
1428
+ n_files_modified += 1
1429
+ n_tokens_removed += len(matches)
1430
+ logger.info(f"[V6.5-V2] Scrubbed {len(matches)} HF token(s) from {py_file}")
1431
+ except Exception as e:
1432
+ logger.warning(f"[V6.5-V2] Could not scan {py_file}: {e}")
1433
+ return {
1434
+ "n_files_scanned": n_files_scanned,
1435
+ "n_files_modified": n_files_modified,
1436
+ "n_tokens_removed": n_tokens_removed,
1437
+ }
1438
+
1439
+
1440
+
1441
+ def main() -> int:
1442
+ import torch
1443
+
1444
+ n_neurons = SOM_GRID[0] * SOM_GRID[1] * SOM_GRID[2] * SOM_GRID[3]
1445
+ print("\n" + "=" * 80)
1446
+ print("V6.5-V2 — 16 HIPÓTESES + 3 TENTATIVAS + 2 FASES (CONHECIMENTO → PUNIÇÃO)")
1447
+ print("=" * 80)
1448
+ print(f" BATCH_SIZE : {BATCH_SIZE}")
1449
+ print(f" STREAM_BATCH_SIZE : {STREAM_BATCH_SIZE} (user: 'de 100 em 100')")
1450
+ print(f" CONHECIMENTO datasets: {len(CONHECIMENTO_DATASETS)}")
1451
+ print(f" PUNICAO dataset : {PUNICAO_DATASET}")
1452
+ print(f" Max samples CONHEC : {MAX_SAMPLES_PER_DATASET_CONHECIMENTO}/dataset")
1453
+ print(f" Max samples PUNICAO : {MAX_SAMPLES_PUNICAO}")
1454
+ print(f" Meta CONHECIMENTO : ≥{META_MINIMA_CONHECIMENTO}")
1455
+ print(f" Meta PUNICAO : ≥{META_MINIMA_PUNICAO}")
1456
+ print(f" SOM grid : {SOM_GRID} ({n_neurons} neurons)")
1457
+ print(f" HIDDEN_DIM : {HIDDEN_DIM}")
1458
+ print(f" VOCAB_SIZE : {VOCAB_SIZE}")
1459
+ print(f" n_hypotheses : {N_HYPOTHESES}")
1460
+ print(f" n_trials : {N_TRIALS}")
1461
+ print(f" hyp_train_steps : {HYP_TRAIN_STEPS}")
1462
+ print(f" Attention : MultiHeadAttention (n_heads=8)")
1463
+ print(f" V65_ENABLE_STREAMING : {os.environ.get('V65_ENABLE_STREAMING')} (REAL)")
1464
+ print(f" Storage critical : {STORAGE_CRITICAL_PCT}%")
1465
+ print(f" Xeon cores : {N_CORES}")
1466
+ print(f" FP16 best TFLOPS : {FP16_BENCH.get('best_tflops', 0.0):.3f}")
1467
+ print("=" * 80 + "\n")
1468
+
1469
+ # 14.1 Verify V2 logic
1470
+ logger.info("[V6.5-V2] Verifying V2 logic (predict + 16 hypotheses + V2 methods)...")
1471
+ verification = verify_v2_logic()
1472
+ print(f"\n--- V2 Logic Verification ---")
1473
+ print(f" PASS: {verification['n_pass']}/{verification['n_pass'] + verification['n_fail']}")
1474
+ for check_name, check_info in verification["checks"].items():
1475
+ status = check_info.get("status", "?")
1476
+ details = check_info.get("details", check_info.get("error", ""))
1477
+ print(f" [{status}] {check_name}: {details[:100]}")
1478
+
1479
+ # 14.2 Initialize KohonenLearningSystemV2 (864 neurons + 16 hypotheses + attention)
1480
+ kls = KohonenLearningSystemV2(
1481
+ vocab_size=VOCAB_SIZE,
1482
+ hidden_dim=HIDDEN_DIM,
1483
+ seq_len=MAX_SEQ_LEN,
1484
+ som_grid=SOM_GRID,
1485
+ alpha0=ALPHA0,
1486
+ sigma0=SIGMA0,
1487
+ lambda_ewc=LAMBDA_EWC,
1488
+ N_start=N_START,
1489
+ dim_choice=DIM_CHOICE,
1490
+ hypothesis_hidden=[512, 256, 128, 64, 32, 16, 8],
1491
+ T_max=T_MAX,
1492
+ enable_vqvae2=False, # V2-dynamic-memory: disabled to save RAM
1493
+ enable_reasoning=True,
1494
+ enable_w8a8=False, # V2-dynamic-memory: disabled to save RAM
1495
+ vqvae2_code_dim=16,
1496
+ vqvae2_num_codes_top=64,
1497
+ vqvae2_num_codes_bot=128,
1498
+ w8a8_alpha=0.5,
1499
+ w8a8_n_bits=8,
1500
+ w8a8_calibration_samples=32,
1501
+ enable_attention=True,
1502
+ attention_n_heads=8,
1503
+ # V2-dynamic parameters (serão adaptados automaticamente)
1504
+ n_hypotheses=N_HYPOTHESES,
1505
+ max_n_hypotheses=MAX_N_HYPOTHESES,
1506
+ min_n_hypotheses=MIN_N_HYPOTHESES,
1507
+ n_trials=N_TRIALS,
1508
+ min_n_trials=MIN_N_TRIALS,
1509
+ max_n_trials=MAX_N_TRIALS,
1510
+ hyp_train_steps=HYP_TRAIN_STEPS,
1511
+ min_hyp_train_steps=MIN_HYP_TRAIN_STEPS,
1512
+ max_hyp_train_steps=MAX_HYP_TRAIN_STEPS,
1513
+ hyp_lr=HYP_LR,
1514
+ hyp_hidden_dim=HYP_HIDDEN_DIM,
1515
+ loss_history_window=LOSS_HISTORY_WINDOW,
1516
+ punishment_window=PUNISHMENT_WINDOW,
1517
+ )
1518
+ logger.info(
1519
+ f"[V6.5-V2-dynamic] KLS V2 initialized: {n_neurons} neurons, "
1520
+ f"hidden={HIDDEN_DIM}, vocab={VOCAB_SIZE}, "
1521
+ f"n_hypotheses={kls.n_hypotheses}/{kls.max_n_hypotheses} "
1522
+ f"(active={kls.hypothesis_ensemble.active_count}), "
1523
+ f"n_trials={kls.n_trials} (limits {kls.min_n_trials}-{kls.max_n_trials}), "
1524
+ f"hyp_train_steps={kls.hyp_train_steps} "
1525
+ f"(limits {kls.min_hyp_train_steps}-{kls.max_hyp_train_steps}), "
1526
+ f"delta_scale={kls.delta_scale.item():.4f}, "
1527
+ f"attention={kls.enable_attention} (n_heads={kls.attention_n_heads}), "
1528
+ f"workers_active={getattr(kls, '_tool_coordinator_workers_active', False)}"
1529
+ )
1530
+
1531
+ # Treina tokenizer com corpus básico PT-BR
1532
+ corpus_inicial = [
1533
+ "o gato dorme na cama", "a casa eh azul", "ele corre rapido",
1534
+ "ela canta uma musica", "o sol nasceu hoje", "nos vamos viajar",
1535
+ "o livro esta na mesa", "a menina brinca no parque",
1536
+ "ola como voce esta", "qual e o seu nome",
1537
+ "calcule dois mais dois", "traduza hello para portugues",
1538
+ "instrucao para resolver o problema", "resposta para a pergunta",
1539
+ "luva de pedreiro tavila", "lula reserva valor",
1540
+ "amazonas forca tarefa vitimas",
1541
+ ]
1542
+ kls.tokenizer.fit(corpus_inicial)
1543
+ logger.info(f"[V6.5-V2] Tokenizer fitted with {len(corpus_inicial)} corpus words")
1544
+
1545
+ # HF_TOKEN
1546
+ hf_token = os.environ.get("HF_TOKEN")
1547
+ if not hf_token:
1548
+ logger.warning("[V6.5-V2] HF_TOKEN not set — streaming may fail for gated datasets")
1549
+ else:
1550
+ logger.info(f"[V6.5-V2] HF_TOKEN set: {hf_token[:8]}...")
1551
+
1552
+ # 14.3 Aggressive storage cleanup before training starts
1553
+ logger.info("[V6.5-V2] Aggressive storage cleanup (pre-training)...")
1554
+ try:
1555
+ storage_cleanup_pre = aggressive_storage_cleanup()
1556
+ aggressive_memory_cleanup()
1557
+ logger.info(
1558
+ f"[V6.5-V2] Pre-training cleanup: "
1559
+ f"{storage_cleanup_pre['n_files_removed']} files, "
1560
+ f"{storage_cleanup_pre['mb_freed']:.1f}MB freed"
1561
+ )
1562
+ except Exception as e:
1563
+ logger.warning(f"[V6.5-V2] Pre-training cleanup failed: {e}")
1564
+ aggressive_memory_cleanup()
1565
+
1566
+ # ========================================================================
1567
+ # 14.4 FASE 1 — CONHECIMENTO (8 datasets, sem punição)
1568
+ # ========================================================================
1569
+ logger.info("\n[V6.5-V2] Iniciando FASE 1 — CONHECIMENTO...")
1570
+ conhecimento_result = run_fase_conhecimento(kls, hf_token)
1571
+ V2_PHASES_EVAL_PATH.write_text(
1572
+ json.dumps({"fase_1_conhecimento": conhecimento_result}, indent=2, ensure_ascii=False)
1573
+ )
1574
+ logger.info(
1575
+ f"\n[V6.5-V2] FASE 1 — CONHECIMENTO finalizada: "
1576
+ f"{conhecimento_result['total_samples']} samples "
1577
+ f"(meta: {conhecimento_result['meta_minima']}, "
1578
+ f"atingida: {conhecimento_result['meta_atingida']})"
1579
+ )
1580
+
1581
+ # Salva estados do modelo após CONHECIMENTO
1582
+ save_model_states_for_evaluation(
1583
+ kls=kls,
1584
+ reason="end_of_fase_conhecimento",
1585
+ step=conhecimento_result["n_steps"],
1586
+ total_samples=conhecimento_result["total_samples"],
1587
+ output_path=BIGRU_ROOT / "v6_5_v2_model_states_after_conhecimento.pt",
1588
+ )
1589
+
1590
+ # Aggressive cleanup entre fases
1591
+ aggressive_memory_cleanup()
1592
+ aggressive_storage_cleanup()
1593
+
1594
+ # ========================================================================
1595
+ # 14.5 FASE 2 — TREINAMENTO COM PUNIÇÃO (BrunoN-Dev/corpus-ptbr-v1, 500 samples)
1596
+ # ========================================================================
1597
+ if not conhecimento_result["storage_critical_stopped"]:
1598
+ logger.info("\n[V6.5-V2] Iniciando FASE 2 — TREINAMENTO COM PUNIÇÃO...")
1599
+ punicão_result = run_fase_punicão(kls, hf_token)
1600
+
1601
+ # Atualiza V2_PHASES_EVAL_PATH com ambas as fases
1602
+ phases_eval = {
1603
+ "fase_1_conhecimento": conhecimento_result,
1604
+ "fase_2_treinamento_com_punicão": punicão_result,
1605
+ }
1606
+ V2_PHASES_EVAL_PATH.write_text(
1607
+ json.dumps(phases_eval, indent=2, ensure_ascii=False)
1608
+ )
1609
+ logger.info(
1610
+ f"\n[V6.5-V2] FASE 2 — PUNIÇÃO finalizada: "
1611
+ f"{punicão_result['total_samples']} samples "
1612
+ f"(meta: {punicão_result['meta_minima']}, "
1613
+ f"atingida: {punicão_result['meta_atingida']})"
1614
+ )
1615
+ logger.info(
1616
+ f"[V6.5-V2] Punishment events: {len(punicão_result['punishment_events'])}, "
1617
+ f"Hypotheses trainings: {len(punicão_result['hypotheses_trainings'])}, "
1618
+ f"Delta applications: {len(punicão_result['delta_applications'])}"
1619
+ )
1620
+ else:
1621
+ punicão_result = {
1622
+ "phase": "TREINAMENTO_COM_PUNICAO",
1623
+ "skipped": True,
1624
+ "reason": "storage_critical_stopped_during_conhecimento",
1625
+ }
1626
+ logger.warning("[V6.5-V2] FASE 2 pulada — storage critical durante CONHECIMENTO.")
1627
+
1628
+ # ========================================================================
1629
+ # 14.6 Salvar estados finais do modelo
1630
+ # ========================================================================
1631
+ logger.info("\n[V6.5-V2] Salvando estados finais do modelo...")
1632
+ total_samples_final = (
1633
+ conhecimento_result["total_samples"] + punicão_result.get("total_samples", 0)
1634
+ )
1635
+ save_info = save_model_states_for_evaluation(
1636
+ kls=kls,
1637
+ reason="end_of_training_v2",
1638
+ step=conhecimento_result["n_steps"] + punicão_result.get("n_steps", 0),
1639
+ total_samples=total_samples_final,
1640
+ )
1641
+
1642
+ # ========================================================================
1643
+ # 14.7 Avaliações finais (attention, predict fix, user questions)
1644
+ # ========================================================================
1645
+ logger.info("\n[V6.5-V2] Avaliando attention...")
1646
+ attention_eval = evaluate_attention(kls)
1647
+ ATTENTION_EVAL_PATH.write_text(json.dumps(attention_eval, indent=2, ensure_ascii=False))
1648
+
1649
+ logger.info("[V6.5-V2] Avaliando predict fix (rótulos dinâmicos)...")
1650
+ predict_fix_eval = evaluate_predict_fix(kls)
1651
+ PREDICT_FIX_EVAL_PATH.write_text(json.dumps(predict_fix_eval, indent=2, ensure_ascii=False))
1652
+
1653
+ logger.info("[V6.5-V2] Lançando 3 perguntas SEM AJUDA ao modelo...")
1654
+ user_questions_eval = launch_user_questions_without_help(kls)
1655
+ USER_QUESTIONS_PATH.write_text(json.dumps(user_questions_eval, indent=2, ensure_ascii=False))
1656
+
1657
+ # ========================================================================
1658
+ # 14.8 Relatório final
1659
+ # ========================================================================
1660
+ final_report = {
1661
+ "version": "V6.5-V2",
1662
+ "timestamp": datetime.now().isoformat(),
1663
+ "config": {
1664
+ "som_grid": list(SOM_GRID),
1665
+ "n_neurons": n_neurons,
1666
+ "hidden_dim": HIDDEN_DIM,
1667
+ "vocab_size": VOCAB_SIZE,
1668
+ "n_hypotheses": N_HYPOTHESES,
1669
+ "n_trials": N_TRIALS,
1670
+ "hyp_train_steps": HYP_TRAIN_STEPS,
1671
+ "stream_batch_size": STREAM_BATCH_SIZE,
1672
+ "meta_conhecimento": META_MINIMA_CONHECIMENTO,
1673
+ "meta_punicão": META_MINIMA_PUNICAO,
1674
+ "conhecimento_datasets": CONHECIMENTO_DATASETS,
1675
+ "punicão_dataset": PUNICAO_DATASET,
1676
+ },
1677
+ "xeon_status": XEON_STATUS,
1678
+ "fp16_benchmark": FP16_BENCH,
1679
+ "v2_verification": verification,
1680
+ "fase_1_conhecimento_summary": {
1681
+ "total_samples": conhecimento_result["total_samples"],
1682
+ "meta_atingida": conhecimento_result["meta_atingida"],
1683
+ "elapsed_s": conhecimento_result["elapsed_s"],
1684
+ "storage_critical_stopped": conhecimento_result["storage_critical_stopped"],
1685
+ },
1686
+ "fase_2_punicão_summary": {
1687
+ "total_samples": punicão_result.get("total_samples", 0),
1688
+ "meta_atingida": punicão_result.get("meta_atingida", False),
1689
+ "elapsed_s": punicão_result.get("elapsed_s", 0.0),
1690
+ "punishment_events": len(punicão_result.get("punishment_events", [])),
1691
+ "hypotheses_trainings": len(punicão_result.get("hypotheses_trainings", [])),
1692
+ "delta_applications": len(punicão_result.get("delta_applications", [])),
1693
+ "skipped": punicão_result.get("skipped", False),
1694
+ },
1695
+ "attention_eval_summary": {
1696
+ "active": attention_eval["active"],
1697
+ "logic_functional": attention_eval["logic_functional"],
1698
+ "n_calls": attention_eval["n_calls"],
1699
+ "assessment": attention_eval["assessment"],
1700
+ },
1701
+ "predict_fix_summary": predict_fix_eval["summary"],
1702
+ "user_questions_summary": user_questions_eval["summary"],
1703
+ "model_states_saved_to": str(MODEL_STATES_PATH),
1704
+ "save_info": save_info,
1705
+ "final_v2_metrics": kls.get_v2_metrics(),
1706
+ }
1707
+ REPORT_PATH.write_text(json.dumps(final_report, indent=2, ensure_ascii=False))
1708
+ logger.info(f"\n[V6.5-V2] Relatório final salvo em: {REPORT_PATH}")
1709
+
1710
+ # Copia arquivos relevantes para download/
1711
+ try:
1712
+ for src in [REPORT_PATH, USER_QUESTIONS_PATH, MODEL_STATES_PATH,
1713
+ V2_PHASES_EVAL_PATH, PREDICT_FIX_EVAL_PATH, ATTENTION_EVAL_PATH,
1714
+ BIGRU_ROOT / "v6_5_v2_model_states_after_conhecimento.pt"]:
1715
+ if src.exists():
1716
+ dst = DOWNLOAD_DIR / src.name
1717
+ shutil.copy2(src, dst)
1718
+ logger.info(f"[V6.5-V2] Copied {src.name} → {dst}")
1719
+ except Exception as e:
1720
+ logger.warning(f"[V6.5-V2] Failed to copy files to download/: {e}")
1721
+
1722
+ # ========================================================================
1723
+ # 14.9 HF BATCH UPLOAD — enviar scripts + estado + modelo ao HF em lote
1724
+ # ========================================================================
1725
+ # User requirement: "após concluir enviar scripts e arquivos e estado
1726
+ # (e treinamento para permitir continuar novo treinamento) do modelo
1727
+ # testados e aprovados sobrescrevendo os antigos desatualizados"
1728
+ upload_report_path = BIGRU_ROOT / "v6_5_v2_upload_report.json"
1729
+ hf_upload_result: Dict[str, Any] = {"uploaded": False, "reason": "skipped"}
1730
+ if hf_token:
1731
+ logger.info("\n[V6.5-V2] Coletando arquivos para upload HF em LOTE...")
1732
+
1733
+ # Scripts a enviar (sobrescrevem antigos no HF)
1734
+ scripts_to_upload: List[Path] = [
1735
+ BIGRU_ROOT / "scripts" / "train_v6_5_v2.py",
1736
+ SRC_ROOT / "bigru_t" / "model" / "kohonen_learning_system.py",
1737
+ SRC_ROOT / "bigru_t" / "model" / "hyp_t.py",
1738
+ SRC_ROOT / "bigru_t" / "data" / "streaming_datasets.py",
1739
+ SRC_ROOT / "bigru_t" / "utils" / "xeon_runtime.py",
1740
+ ]
1741
+ # Relatórios + estados
1742
+ outputs_to_upload: List[Path] = [
1743
+ REPORT_PATH,
1744
+ MODEL_STATES_PATH,
1745
+ V2_PHASES_EVAL_PATH,
1746
+ PREDICT_FIX_EVAL_PATH,
1747
+ ATTENTION_EVAL_PATH,
1748
+ USER_QUESTIONS_PATH,
1749
+ BIGRU_ROOT / "v6_5_v2_model_states_after_conhecimento.pt",
1750
+ ]
1751
+ # Filtra os que existem
1752
+ all_files: List[Path] = []
1753
+ for p in scripts_to_upload + outputs_to_upload:
1754
+ if p.exists():
1755
+ all_files.append(p)
1756
+ else:
1757
+ logger.warning(f"[V6.5-V2] Upload file not found: {p}")
1758
+
1759
+ # Apaga HF_TOKEN dos scripts ANTES do upload (não enviar tokens)
1760
+ scrub_result = scrub_hf_token_from_scripts(BIGRU_ROOT / "scripts")
1761
+ scrub_result_src = scrub_hf_token_from_scripts(SRC_ROOT)
1762
+ logger.info(
1763
+ f"[V6.5-V2] Token scrub: scripts={scrub_result}, src={scrub_result_src}"
1764
+ )
1765
+
1766
+ # Upload em LOTE
1767
+ hf_upload_result = upload_to_hf_batch(
1768
+ hf_token=hf_token,
1769
+ files_to_upload=all_files,
1770
+ repo_id=HF_REPO_ID,
1771
+ repo_type="model",
1772
+ )
1773
+ upload_report_path.write_text(
1774
+ json.dumps(hf_upload_result, indent=2, ensure_ascii=False)
1775
+ )
1776
+ logger.info(f"[V6.5-V2] HF upload report saved: {upload_report_path}")
1777
+ if upload_report_path.exists():
1778
+ shutil.copy2(upload_report_path, DOWNLOAD_DIR / upload_report_path.name)
1779
+ else:
1780
+ logger.warning("[V6.5-V2] HF_TOKEN não disponível — pulando upload HF.")
1781
+
1782
+ # ========================================================================
1783
+ # 14.10 LIMPEZA HF_TOKEN do ambiente (user requirement)
1784
+ # ========================================================================
1785
+ logger.info("\n[V6.5-V2] Limpando HF_TOKEN do ambiente...")
1786
+ if "HF_TOKEN" in os.environ:
1787
+ del os.environ["HF_TOKEN"]
1788
+ logger.info("[V6.5-V2] HF_TOKEN removido do ambiente.")
1789
+ if "HUGGING_FACE_HUB_TOKEN" in os.environ:
1790
+ del os.environ["HUGGING_FACE_HUB_TOKEN"]
1791
+ logger.info("[V6.5-V2] HUGGING_FACE_HUB_TOKEN removido do ambiente.")
1792
+ # Re-scrub após o upload (segurança extra)
1793
+ final_scrub = scrub_hf_token_from_scripts(BIGRU_ROOT / "scripts")
1794
+ final_scrub_src = scrub_hf_token_from_scripts(SRC_ROOT)
1795
+ final_scrub_proj = scrub_hf_token_from_scripts(PROJECT_ROOT / "scripts")
1796
+
1797
+ # ========================================================================
1798
+ # 14.11 LIMPEZA final de armazenamento e worklog
1799
+ # ========================================================================
1800
+ logger.info("\n[V6.5-V2] Limpeza final de armazenamento...")
1801
+ final_storage_cleanup = aggressive_storage_cleanup()
1802
+ aggressive_memory_cleanup()
1803
+
1804
+ print("\n" + "=" * 80)
1805
+ print("V6.5-V2-dynamic — TREINAMENTO CONCLUÍDO")
1806
+ print("=" * 80)
1807
+ print(f" FASE 1 CONHECIMENTO : {conhecimento_result['total_samples']} samples "
1808
+ f"(meta: {conhecimento_result['meta_atingida']})")
1809
+ print(f" FASE 2 PUNICAO : {punicão_result.get('total_samples', 0)} samples "
1810
+ f"(meta: {punicão_result.get('meta_atingida', False)})")
1811
+ print(f" Punishment events : {len(punicão_result.get('punishment_events', []))}")
1812
+ print(f" Delta applications : {len(punicão_result.get('delta_applications', []))}")
1813
+ print(f" Attention functional: {attention_eval['logic_functional']}")
1814
+ print(f" Predict fix verified: {predict_fix_eval['summary']['predict_fix_verified']}")
1815
+ print(f" User questions ans : {user_questions_eval['summary']['n_with_answer']}/3")
1816
+ print(f" HF upload : {hf_upload_result.get('uploaded', False)} "
1817
+ f"({hf_upload_result.get('n_files', 0)} files)")
1818
+ print(f" HF_TOKEN cleaned : True (env + scripts)")
1819
+ print(f" Storage cleanup : {final_storage_cleanup['n_files_removed']} files, "
1820
+ f"{final_storage_cleanup['mb_freed']:.1f}MB freed")
1821
+ print(f" Final n_hypotheses : {kls.n_hypotheses} (active={kls.hypothesis_ensemble.active_count})")
1822
+ print(f" Final n_trials : {kls.n_trials}")
1823
+ print(f" Final hyp_steps : {kls.hyp_train_steps}")
1824
+ print(f" N adaptations : {len(kls.get_adaptation_log())}")
1825
+ print("=" * 80 + "\n")
1826
+
1827
+ return 0
1828
+
1829
+
1830
+ if __name__ == "__main__":
1831
+ sys.exit(main())
v6_5_v2_attention_eval.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": 3441,
7
+ "n_errors": 0,
8
+ "last_norm_in": 54.769012451171875,
9
+ "last_norm_out": 56.71458053588867,
10
+ "last_attn_activated": true,
11
+ "last_attn_diff_norm": 56.80364227294922,
12
+ "n_heads": 8,
13
+ "logic_functional": true
14
+ },
15
+ "active": true,
16
+ "logic_functional": true,
17
+ "n_calls": 3441,
18
+ "n_errors": 0,
19
+ "n_heads": 8,
20
+ "assessment": "PASS"
21
+ }
v6_5_v2_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:43a1a29a3556c5960c661c103aecb3322ea32b50d7afc45d254d21b203f98f20
3
+ size 40959502
v6_5_v2_model_states_after_conhecimento.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4bc13a9ef5d19ba56d3eecee92716f76696ffcb7924b0b64c981327e066922ec
3
+ size 40963993
v6_5_v2_phases_eval.json ADDED
@@ -0,0 +1,784 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fase_1_conhecimento": {
3
+ "phase": "CONHECIMENTO",
4
+ "total_samples": 3300,
5
+ "meta_minima": 6000,
6
+ "meta_atingida": false,
7
+ "samples_per_dataset": {
8
+ "dominguesm/restore-punctuation-ptbr-dataset": 800,
9
+ "carolina-c4ai/corpus-carolina": 800,
10
+ "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1": 800,
11
+ "dominguesm/Canarim-Instruct-PTBR-Dataset": 800,
12
+ "adalbertojunior/punctuation-ptbr": 100,
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": 425.32095551490784,
29
+ "n_steps": 225,
30
+ "n_chunks": 33,
31
+ "accuracies_log": [
32
+ {
33
+ "step": 175,
34
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
35
+ "chunk_idx": 26,
36
+ "batch_size": 16,
37
+ "accuracy": 0.5514705882352942,
38
+ "phase": "CONHECIMENTO",
39
+ "buffer_size": 272,
40
+ "training_ready": true,
41
+ "elapsed_ms": 260.0207328796387
42
+ },
43
+ {
44
+ "step": 176,
45
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
46
+ "chunk_idx": 26,
47
+ "batch_size": 16,
48
+ "accuracy": 0.5208333333333334,
49
+ "phase": "CONHECIMENTO",
50
+ "buffer_size": 288,
51
+ "training_ready": true,
52
+ "elapsed_ms": 269.819974899292
53
+ },
54
+ {
55
+ "step": 177,
56
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
57
+ "chunk_idx": 26,
58
+ "batch_size": 16,
59
+ "accuracy": 0.506578947368421,
60
+ "phase": "CONHECIMENTO",
61
+ "buffer_size": 304,
62
+ "training_ready": true,
63
+ "elapsed_ms": 276.5047550201416
64
+ },
65
+ {
66
+ "step": 178,
67
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
68
+ "chunk_idx": 26,
69
+ "batch_size": 16,
70
+ "accuracy": 0.53125,
71
+ "phase": "CONHECIMENTO",
72
+ "buffer_size": 320,
73
+ "training_ready": true,
74
+ "elapsed_ms": 286.62753105163574
75
+ },
76
+ {
77
+ "step": 179,
78
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
79
+ "chunk_idx": 26,
80
+ "batch_size": 16,
81
+ "accuracy": 0.5535714285714286,
82
+ "phase": "CONHECIMENTO",
83
+ "buffer_size": 336,
84
+ "training_ready": true,
85
+ "elapsed_ms": 285.3672504425049
86
+ },
87
+ {
88
+ "step": 180,
89
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
90
+ "chunk_idx": 26,
91
+ "batch_size": 16,
92
+ "accuracy": 0.5738636363636364,
93
+ "phase": "CONHECIMENTO",
94
+ "buffer_size": 352,
95
+ "training_ready": true,
96
+ "elapsed_ms": 312.63208389282227
97
+ },
98
+ {
99
+ "step": 181,
100
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
101
+ "chunk_idx": 26,
102
+ "batch_size": 4,
103
+ "accuracy": 0.5786516853932584,
104
+ "phase": "CONHECIMENTO",
105
+ "buffer_size": 356,
106
+ "training_ready": true,
107
+ "elapsed_ms": 304.9945831298828
108
+ },
109
+ {
110
+ "step": 182,
111
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
112
+ "chunk_idx": 27,
113
+ "batch_size": 16,
114
+ "accuracy": 0.8088235294117647,
115
+ "phase": "CONHECIMENTO",
116
+ "buffer_size": 272,
117
+ "training_ready": true,
118
+ "elapsed_ms": 260.9591484069824
119
+ },
120
+ {
121
+ "step": 183,
122
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
123
+ "chunk_idx": 27,
124
+ "batch_size": 16,
125
+ "accuracy": 0.8194444444444444,
126
+ "phase": "CONHECIMENTO",
127
+ "buffer_size": 288,
128
+ "training_ready": true,
129
+ "elapsed_ms": 293.58363151550293
130
+ },
131
+ {
132
+ "step": 184,
133
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
134
+ "chunk_idx": 27,
135
+ "batch_size": 16,
136
+ "accuracy": 0.8289473684210527,
137
+ "phase": "CONHECIMENTO",
138
+ "buffer_size": 304,
139
+ "training_ready": true,
140
+ "elapsed_ms": 275.958776473999
141
+ },
142
+ {
143
+ "step": 185,
144
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
145
+ "chunk_idx": 27,
146
+ "batch_size": 16,
147
+ "accuracy": 0.8375,
148
+ "phase": "CONHECIMENTO",
149
+ "buffer_size": 320,
150
+ "training_ready": true,
151
+ "elapsed_ms": 290.9085750579834
152
+ },
153
+ {
154
+ "step": 186,
155
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
156
+ "chunk_idx": 27,
157
+ "batch_size": 16,
158
+ "accuracy": 0.8452380952380952,
159
+ "phase": "CONHECIMENTO",
160
+ "buffer_size": 336,
161
+ "training_ready": true,
162
+ "elapsed_ms": 438.265323638916
163
+ },
164
+ {
165
+ "step": 187,
166
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
167
+ "chunk_idx": 27,
168
+ "batch_size": 16,
169
+ "accuracy": 0.8522727272727273,
170
+ "phase": "CONHECIMENTO",
171
+ "buffer_size": 352,
172
+ "training_ready": true,
173
+ "elapsed_ms": 363.4645938873291
174
+ },
175
+ {
176
+ "step": 188,
177
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
178
+ "chunk_idx": 27,
179
+ "batch_size": 4,
180
+ "accuracy": 0.8539325842696629,
181
+ "phase": "CONHECIMENTO",
182
+ "buffer_size": 356,
183
+ "training_ready": true,
184
+ "elapsed_ms": 308.2740306854248
185
+ },
186
+ {
187
+ "step": 189,
188
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
189
+ "chunk_idx": 28,
190
+ "batch_size": 16,
191
+ "accuracy": 1.0,
192
+ "phase": "CONHECIMENTO",
193
+ "buffer_size": 272,
194
+ "training_ready": true,
195
+ "elapsed_ms": 387.5901699066162
196
+ },
197
+ {
198
+ "step": 190,
199
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
200
+ "chunk_idx": 28,
201
+ "batch_size": 16,
202
+ "accuracy": 1.0,
203
+ "phase": "CONHECIMENTO",
204
+ "buffer_size": 288,
205
+ "training_ready": true,
206
+ "elapsed_ms": 268.2316303253174
207
+ },
208
+ {
209
+ "step": 191,
210
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
211
+ "chunk_idx": 28,
212
+ "batch_size": 16,
213
+ "accuracy": 1.0,
214
+ "phase": "CONHECIMENTO",
215
+ "buffer_size": 304,
216
+ "training_ready": true,
217
+ "elapsed_ms": 279.0110111236572
218
+ },
219
+ {
220
+ "step": 192,
221
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
222
+ "chunk_idx": 28,
223
+ "batch_size": 16,
224
+ "accuracy": 1.0,
225
+ "phase": "CONHECIMENTO",
226
+ "buffer_size": 320,
227
+ "training_ready": true,
228
+ "elapsed_ms": 561.1886978149414
229
+ },
230
+ {
231
+ "step": 193,
232
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
233
+ "chunk_idx": 28,
234
+ "batch_size": 16,
235
+ "accuracy": 1.0,
236
+ "phase": "CONHECIMENTO",
237
+ "buffer_size": 336,
238
+ "training_ready": true,
239
+ "elapsed_ms": 361.0963821411133
240
+ },
241
+ {
242
+ "step": 194,
243
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
244
+ "chunk_idx": 28,
245
+ "batch_size": 16,
246
+ "accuracy": 1.0,
247
+ "phase": "CONHECIMENTO",
248
+ "buffer_size": 352,
249
+ "training_ready": true,
250
+ "elapsed_ms": 353.18779945373535
251
+ },
252
+ {
253
+ "step": 195,
254
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
255
+ "chunk_idx": 28,
256
+ "batch_size": 4,
257
+ "accuracy": 1.0,
258
+ "phase": "CONHECIMENTO",
259
+ "buffer_size": 356,
260
+ "training_ready": true,
261
+ "elapsed_ms": 302.43706703186035
262
+ },
263
+ {
264
+ "step": 196,
265
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
266
+ "chunk_idx": 29,
267
+ "batch_size": 16,
268
+ "accuracy": 1.0,
269
+ "phase": "CONHECIMENTO",
270
+ "buffer_size": 272,
271
+ "training_ready": true,
272
+ "elapsed_ms": 275.22897720336914
273
+ },
274
+ {
275
+ "step": 197,
276
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
277
+ "chunk_idx": 29,
278
+ "batch_size": 16,
279
+ "accuracy": 1.0,
280
+ "phase": "CONHECIMENTO",
281
+ "buffer_size": 288,
282
+ "training_ready": true,
283
+ "elapsed_ms": 405.1165580749512
284
+ },
285
+ {
286
+ "step": 198,
287
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
288
+ "chunk_idx": 29,
289
+ "batch_size": 16,
290
+ "accuracy": 1.0,
291
+ "phase": "CONHECIMENTO",
292
+ "buffer_size": 304,
293
+ "training_ready": true,
294
+ "elapsed_ms": 280.89165687561035
295
+ },
296
+ {
297
+ "step": 199,
298
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
299
+ "chunk_idx": 29,
300
+ "batch_size": 16,
301
+ "accuracy": 1.0,
302
+ "phase": "CONHECIMENTO",
303
+ "buffer_size": 320,
304
+ "training_ready": true,
305
+ "elapsed_ms": 294.2771911621094
306
+ },
307
+ {
308
+ "step": 200,
309
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
310
+ "chunk_idx": 29,
311
+ "batch_size": 16,
312
+ "accuracy": 1.0,
313
+ "phase": "CONHECIMENTO",
314
+ "buffer_size": 336,
315
+ "training_ready": true,
316
+ "elapsed_ms": 341.6149616241455
317
+ },
318
+ {
319
+ "step": 201,
320
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
321
+ "chunk_idx": 29,
322
+ "batch_size": 16,
323
+ "accuracy": 1.0,
324
+ "phase": "CONHECIMENTO",
325
+ "buffer_size": 352,
326
+ "training_ready": true,
327
+ "elapsed_ms": 612.4014854431152
328
+ },
329
+ {
330
+ "step": 202,
331
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
332
+ "chunk_idx": 29,
333
+ "batch_size": 4,
334
+ "accuracy": 1.0,
335
+ "phase": "CONHECIMENTO",
336
+ "buffer_size": 356,
337
+ "training_ready": true,
338
+ "elapsed_ms": 304.2721748352051
339
+ },
340
+ {
341
+ "step": 203,
342
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
343
+ "chunk_idx": 30,
344
+ "batch_size": 16,
345
+ "accuracy": 1.0,
346
+ "phase": "CONHECIMENTO",
347
+ "buffer_size": 272,
348
+ "training_ready": true,
349
+ "elapsed_ms": 261.81983947753906
350
+ },
351
+ {
352
+ "step": 204,
353
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
354
+ "chunk_idx": 30,
355
+ "batch_size": 16,
356
+ "accuracy": 1.0,
357
+ "phase": "CONHECIMENTO",
358
+ "buffer_size": 288,
359
+ "training_ready": true,
360
+ "elapsed_ms": 264.61100578308105
361
+ },
362
+ {
363
+ "step": 205,
364
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
365
+ "chunk_idx": 30,
366
+ "batch_size": 16,
367
+ "accuracy": 1.0,
368
+ "phase": "CONHECIMENTO",
369
+ "buffer_size": 304,
370
+ "training_ready": true,
371
+ "elapsed_ms": 274.2750644683838
372
+ },
373
+ {
374
+ "step": 206,
375
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
376
+ "chunk_idx": 30,
377
+ "batch_size": 16,
378
+ "accuracy": 1.0,
379
+ "phase": "CONHECIMENTO",
380
+ "buffer_size": 320,
381
+ "training_ready": true,
382
+ "elapsed_ms": 291.9497489929199
383
+ },
384
+ {
385
+ "step": 207,
386
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
387
+ "chunk_idx": 30,
388
+ "batch_size": 16,
389
+ "accuracy": 1.0,
390
+ "phase": "CONHECIMENTO",
391
+ "buffer_size": 336,
392
+ "training_ready": true,
393
+ "elapsed_ms": 409.27672386169434
394
+ },
395
+ {
396
+ "step": 208,
397
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
398
+ "chunk_idx": 30,
399
+ "batch_size": 16,
400
+ "accuracy": 1.0,
401
+ "phase": "CONHECIMENTO",
402
+ "buffer_size": 352,
403
+ "training_ready": true,
404
+ "elapsed_ms": 300.47035217285156
405
+ },
406
+ {
407
+ "step": 209,
408
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
409
+ "chunk_idx": 30,
410
+ "batch_size": 4,
411
+ "accuracy": 1.0,
412
+ "phase": "CONHECIMENTO",
413
+ "buffer_size": 356,
414
+ "training_ready": true,
415
+ "elapsed_ms": 296.6763973236084
416
+ },
417
+ {
418
+ "step": 210,
419
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
420
+ "chunk_idx": 31,
421
+ "batch_size": 16,
422
+ "accuracy": 1.0,
423
+ "phase": "CONHECIMENTO",
424
+ "buffer_size": 272,
425
+ "training_ready": true,
426
+ "elapsed_ms": 253.9806365966797
427
+ },
428
+ {
429
+ "step": 211,
430
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
431
+ "chunk_idx": 31,
432
+ "batch_size": 16,
433
+ "accuracy": 1.0,
434
+ "phase": "CONHECIMENTO",
435
+ "buffer_size": 288,
436
+ "training_ready": true,
437
+ "elapsed_ms": 234.45916175842285
438
+ },
439
+ {
440
+ "step": 212,
441
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
442
+ "chunk_idx": 31,
443
+ "batch_size": 16,
444
+ "accuracy": 1.0,
445
+ "phase": "CONHECIMENTO",
446
+ "buffer_size": 304,
447
+ "training_ready": true,
448
+ "elapsed_ms": 271.76856994628906
449
+ },
450
+ {
451
+ "step": 213,
452
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
453
+ "chunk_idx": 31,
454
+ "batch_size": 16,
455
+ "accuracy": 1.0,
456
+ "phase": "CONHECIMENTO",
457
+ "buffer_size": 320,
458
+ "training_ready": true,
459
+ "elapsed_ms": 292.76251792907715
460
+ },
461
+ {
462
+ "step": 214,
463
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
464
+ "chunk_idx": 31,
465
+ "batch_size": 16,
466
+ "accuracy": 1.0,
467
+ "phase": "CONHECIMENTO",
468
+ "buffer_size": 336,
469
+ "training_ready": true,
470
+ "elapsed_ms": 297.0712184906006
471
+ },
472
+ {
473
+ "step": 215,
474
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
475
+ "chunk_idx": 31,
476
+ "batch_size": 16,
477
+ "accuracy": 1.0,
478
+ "phase": "CONHECIMENTO",
479
+ "buffer_size": 352,
480
+ "training_ready": true,
481
+ "elapsed_ms": 329.21457290649414
482
+ },
483
+ {
484
+ "step": 216,
485
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
486
+ "chunk_idx": 31,
487
+ "batch_size": 4,
488
+ "accuracy": 1.0,
489
+ "phase": "CONHECIMENTO",
490
+ "buffer_size": 356,
491
+ "training_ready": true,
492
+ "elapsed_ms": 318.44639778137207
493
+ },
494
+ {
495
+ "step": 217,
496
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
497
+ "chunk_idx": 32,
498
+ "batch_size": 16,
499
+ "accuracy": 1.0,
500
+ "phase": "CONHECIMENTO",
501
+ "buffer_size": 272,
502
+ "training_ready": true,
503
+ "elapsed_ms": 367.6486015319824
504
+ },
505
+ {
506
+ "step": 218,
507
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
508
+ "chunk_idx": 32,
509
+ "batch_size": 16,
510
+ "accuracy": 1.0,
511
+ "phase": "CONHECIMENTO",
512
+ "buffer_size": 288,
513
+ "training_ready": true,
514
+ "elapsed_ms": 270.40815353393555
515
+ },
516
+ {
517
+ "step": 219,
518
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
519
+ "chunk_idx": 32,
520
+ "batch_size": 16,
521
+ "accuracy": 1.0,
522
+ "phase": "CONHECIMENTO",
523
+ "buffer_size": 304,
524
+ "training_ready": true,
525
+ "elapsed_ms": 289.8850440979004
526
+ },
527
+ {
528
+ "step": 220,
529
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
530
+ "chunk_idx": 32,
531
+ "batch_size": 16,
532
+ "accuracy": 1.0,
533
+ "phase": "CONHECIMENTO",
534
+ "buffer_size": 320,
535
+ "training_ready": true,
536
+ "elapsed_ms": 294.964075088501
537
+ },
538
+ {
539
+ "step": 221,
540
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
541
+ "chunk_idx": 32,
542
+ "batch_size": 16,
543
+ "accuracy": 1.0,
544
+ "phase": "CONHECIMENTO",
545
+ "buffer_size": 336,
546
+ "training_ready": true,
547
+ "elapsed_ms": 304.9020767211914
548
+ },
549
+ {
550
+ "step": 222,
551
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
552
+ "chunk_idx": 32,
553
+ "batch_size": 16,
554
+ "accuracy": 1.0,
555
+ "phase": "CONHECIMENTO",
556
+ "buffer_size": 352,
557
+ "training_ready": true,
558
+ "elapsed_ms": 395.02906799316406
559
+ },
560
+ {
561
+ "step": 223,
562
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
563
+ "chunk_idx": 32,
564
+ "batch_size": 4,
565
+ "accuracy": 1.0,
566
+ "phase": "CONHECIMENTO",
567
+ "buffer_size": 356,
568
+ "training_ready": true,
569
+ "elapsed_ms": 313.39168548583984
570
+ },
571
+ {
572
+ "step": 224,
573
+ "dataset": "adalbertojunior/punctuation-ptbr",
574
+ "chunk_idx": 33,
575
+ "batch_size": 16,
576
+ "accuracy": 0.9448529411764706,
577
+ "phase": "CONHECIMENTO",
578
+ "buffer_size": 272,
579
+ "training_ready": true,
580
+ "elapsed_ms": 238.13128471374512
581
+ }
582
+ ],
583
+ "attention_log": [
584
+ {
585
+ "step": 204,
586
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
587
+ "n_calls": 3137,
588
+ "n_errors": 0,
589
+ "last_attn_activated": true,
590
+ "logic_functional": true
591
+ },
592
+ {
593
+ "step": 205,
594
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
595
+ "n_calls": 3154,
596
+ "n_errors": 0,
597
+ "last_attn_activated": true,
598
+ "logic_functional": true
599
+ },
600
+ {
601
+ "step": 206,
602
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
603
+ "n_calls": 3171,
604
+ "n_errors": 0,
605
+ "last_attn_activated": true,
606
+ "logic_functional": true
607
+ },
608
+ {
609
+ "step": 207,
610
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
611
+ "n_calls": 3188,
612
+ "n_errors": 0,
613
+ "last_attn_activated": true,
614
+ "logic_functional": true
615
+ },
616
+ {
617
+ "step": 208,
618
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
619
+ "n_calls": 3205,
620
+ "n_errors": 0,
621
+ "last_attn_activated": true,
622
+ "logic_functional": true
623
+ },
624
+ {
625
+ "step": 209,
626
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
627
+ "n_calls": 3210,
628
+ "n_errors": 0,
629
+ "last_attn_activated": true,
630
+ "logic_functional": true
631
+ },
632
+ {
633
+ "step": 210,
634
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
635
+ "n_calls": 3227,
636
+ "n_errors": 0,
637
+ "last_attn_activated": true,
638
+ "logic_functional": true
639
+ },
640
+ {
641
+ "step": 211,
642
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
643
+ "n_calls": 3244,
644
+ "n_errors": 0,
645
+ "last_attn_activated": true,
646
+ "logic_functional": true
647
+ },
648
+ {
649
+ "step": 212,
650
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
651
+ "n_calls": 3261,
652
+ "n_errors": 0,
653
+ "last_attn_activated": true,
654
+ "logic_functional": true
655
+ },
656
+ {
657
+ "step": 213,
658
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
659
+ "n_calls": 3278,
660
+ "n_errors": 0,
661
+ "last_attn_activated": true,
662
+ "logic_functional": true
663
+ },
664
+ {
665
+ "step": 214,
666
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
667
+ "n_calls": 3295,
668
+ "n_errors": 0,
669
+ "last_attn_activated": true,
670
+ "logic_functional": true
671
+ },
672
+ {
673
+ "step": 215,
674
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
675
+ "n_calls": 3312,
676
+ "n_errors": 0,
677
+ "last_attn_activated": true,
678
+ "logic_functional": true
679
+ },
680
+ {
681
+ "step": 216,
682
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
683
+ "n_calls": 3317,
684
+ "n_errors": 0,
685
+ "last_attn_activated": true,
686
+ "logic_functional": true
687
+ },
688
+ {
689
+ "step": 217,
690
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
691
+ "n_calls": 3334,
692
+ "n_errors": 0,
693
+ "last_attn_activated": true,
694
+ "logic_functional": true
695
+ },
696
+ {
697
+ "step": 218,
698
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
699
+ "n_calls": 3351,
700
+ "n_errors": 0,
701
+ "last_attn_activated": true,
702
+ "logic_functional": true
703
+ },
704
+ {
705
+ "step": 219,
706
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
707
+ "n_calls": 3368,
708
+ "n_errors": 0,
709
+ "last_attn_activated": true,
710
+ "logic_functional": true
711
+ },
712
+ {
713
+ "step": 220,
714
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
715
+ "n_calls": 3385,
716
+ "n_errors": 0,
717
+ "last_attn_activated": true,
718
+ "logic_functional": true
719
+ },
720
+ {
721
+ "step": 221,
722
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
723
+ "n_calls": 3402,
724
+ "n_errors": 0,
725
+ "last_attn_activated": true,
726
+ "logic_functional": true
727
+ },
728
+ {
729
+ "step": 222,
730
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
731
+ "n_calls": 3419,
732
+ "n_errors": 0,
733
+ "last_attn_activated": true,
734
+ "logic_functional": true
735
+ },
736
+ {
737
+ "step": 224,
738
+ "dataset": "adalbertojunior/punctuation-ptbr",
739
+ "n_calls": 3441,
740
+ "n_errors": 0,
741
+ "last_attn_activated": true,
742
+ "logic_functional": true
743
+ }
744
+ ],
745
+ "final_state": {
746
+ "version": "V2-dynamic",
747
+ "n_hypotheses": 8,
748
+ "n_hypotheses_active": 8,
749
+ "max_n_hypotheses": 16,
750
+ "n_trials": 3,
751
+ "hyp_train_steps": 20,
752
+ "hyp_lr": 0.0001,
753
+ "delta_scale": 0.009999999776482582,
754
+ "n_generators": 16,
755
+ "punishment_count": 0,
756
+ "success_count": 0,
757
+ "training_ready": true,
758
+ "classifier_trained": false,
759
+ "ewc_reference_set": false,
760
+ "buffer_size": 256,
761
+ "dynamic_adaptation": {
762
+ "loss_history_len": 0,
763
+ "loss_stats": {
764
+ "slope": 0.0,
765
+ "volatility": 0.0,
766
+ "mean": 0.0,
767
+ "n": 0
768
+ },
769
+ "punishment_rate": 0.0,
770
+ "punishment_window_size": 0,
771
+ "n_adaptations": 0,
772
+ "limits": {
773
+ "min_n_hypotheses": 4,
774
+ "max_n_hypotheses": 16,
775
+ "min_n_trials": 1,
776
+ "max_n_trials": 6,
777
+ "min_hyp_train_steps": 5,
778
+ "max_hyp_train_steps": 60
779
+ },
780
+ "last_5_adaptations": []
781
+ }
782
+ }
783
+ }
784
+ }
v6_5_v2_predict_fix_eval.json ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": "unpunctuated",
9
+ "probability": 0.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": "unpunctuated",
18
+ "probability": 0.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": "unpunctuated",
27
+ "probability": 0.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": "unpunctuated",
36
+ "probability": 0.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": "unpunctuated",
45
+ "probability": 0.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": "unpunctuated",
54
+ "probability": 0.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": "unpunctuated",
69
+ "valid_for_dataset": true
70
+ },
71
+ {
72
+ "dataset": "carolina-c4ai/corpus-carolina",
73
+ "expected_labels": [
74
+ "raw_corpus",
75
+ "normalized_text"
76
+ ],
77
+ "prediction": "raw_corpus",
78
+ "valid_for_dataset": true
79
+ },
80
+ {
81
+ "dataset": "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1",
82
+ "expected_labels": [
83
+ "user_turn",
84
+ "assistant_turn"
85
+ ],
86
+ "prediction": "user_turn",
87
+ "valid_for_dataset": true
88
+ },
89
+ {
90
+ "dataset": "dominguesm/Canarim-Instruct-PTBR-Dataset",
91
+ "expected_labels": [
92
+ "instruction",
93
+ "response"
94
+ ],
95
+ "prediction": "instruction",
96
+ "valid_for_dataset": true
97
+ },
98
+ {
99
+ "dataset": "adalbertojunior/punctuation-ptbr",
100
+ "expected_labels": [
101
+ "unpunctuated",
102
+ "punctuated"
103
+ ],
104
+ "prediction": "unpunctuated",
105
+ "valid_for_dataset": true
106
+ }
107
+ ],
108
+ "summary": {
109
+ "n_returns_gato": 0,
110
+ "n_returns_cachorro": 0,
111
+ "n_returns_registry_label": 6,
112
+ "n_returns_default_label": 0,
113
+ "hardcoded_bug_present": false,
114
+ "predict_fix_verified": true
115
+ },
116
+ "quality_assessment": {
117
+ "fix_status": "PASS",
118
+ "note": "predict() não retorna mais 'gato'/'cachorro' fixos — usa label_registry dinâmico."
119
+ }
120
+ }
v6_5_v2_report.json ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "V6.5-V2",
3
+ "timestamp": "2026-08-08T21:26:39.965059",
4
+ "config": {
5
+ "som_grid": [
6
+ 6,
7
+ 6,
8
+ 6,
9
+ 4
10
+ ],
11
+ "n_neurons": 864,
12
+ "hidden_dim": 256,
13
+ "vocab_size": 4096,
14
+ "n_hypotheses": 8,
15
+ "n_trials": 3,
16
+ "hyp_train_steps": 20,
17
+ "stream_batch_size": 100,
18
+ "meta_conhecimento": 6000,
19
+ "meta_punicão": 1000,
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": 94.09655899980862,
58
+ "avg_time_ms": 97.57540749978943,
59
+ "best_tflops": 1.3603047907443706,
60
+ "avg_tflops": 1.3118059486482412,
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": 3300,
88
+ "meta_atingida": false,
89
+ "elapsed_s": 425.32095551490784,
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": 3441,
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": 3,
118
+ "answer_rate": 1.0,
119
+ "think_rate": 1.0,
120
+ "avg_latency_ms": 3.060022989908854,
121
+ "avg_reasoning_length": 1030.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": 40.959502,
128
+ "reason": "end_of_training_v2",
129
+ "step": 225,
130
+ "total_samples": 3300,
131
+ "n_tensors": 7,
132
+ "n_buffer_tail": 128
133
+ },
134
+ "final_v2_metrics": {
135
+ "version": "V2-dynamic",
136
+ "n_hypotheses": 8,
137
+ "n_hypotheses_active": 8,
138
+ "max_n_hypotheses": 16,
139
+ "n_trials": 3,
140
+ "hyp_train_steps": 20,
141
+ "hyp_lr": 0.0001,
142
+ "delta_scale": 0.009999999776482582,
143
+ "n_generators": 16,
144
+ "punishment_count": 0,
145
+ "success_count": 0,
146
+ "training_ready": true,
147
+ "classifier_trained": false,
148
+ "ewc_reference_set": false,
149
+ "buffer_size": 256,
150
+ "dynamic_adaptation": {
151
+ "loss_history_len": 0,
152
+ "loss_stats": {
153
+ "slope": 0.0,
154
+ "volatility": 0.0,
155
+ "mean": 0.0,
156
+ "n": 0
157
+ },
158
+ "punishment_rate": 0.0,
159
+ "punishment_window_size": 0,
160
+ "n_adaptations": 0,
161
+ "limits": {
162
+ "min_n_hypotheses": 4,
163
+ "max_n_hypotheses": 16,
164
+ "min_n_trials": 1,
165
+ "max_n_trials": 6,
166
+ "min_hyp_train_steps": 5,
167
+ "max_hyp_train_steps": 60
168
+ },
169
+ "last_5_adaptations": []
170
+ }
171
+ }
172
+ }
v6_5_v2_user_questions.json ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": "unpunctuated",
22
+ "reasoning_length": 1028,
23
+ "has_think": true,
24
+ "has_plan": true,
25
+ "has_answer": true,
26
+ "has_decompose": true,
27
+ "think_preview": "Analisando a query: 'Luva de Pedreiro Távila'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.",
28
+ "answer_preview": "prediction=unpunctuated | BMU=(4, 4, 5, 0)",
29
+ "raw_response_preview": "<think>\nAnalisando a query: 'Luva de Pedreiro Távila'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.\n</think>\n<plan>\nPlano de resolução:\n1. Decompor o problema em sub-tarefas\n2. Identificar ferramentas necessárias (disponíveis: som_query, buffer_stats)\n3. Executar sub-tarefas em sequência\n4. Monitorar resultados\n5. Compor resposta final\n</plan>\n<decompose>\n- Processar: Luva de Pedreiro Távila\n</decompose>\n<execute>\nSub-tarefa 'Processar: Luva de Pedre...",
30
+ "n_tags": 4,
31
+ "latency_ms": 3.1023025512695312
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": "unpunctuated",
40
+ "reasoning_length": 998,
41
+ "has_think": true,
42
+ "has_plan": true,
43
+ "has_answer": true,
44
+ "has_decompose": true,
45
+ "think_preview": "Analisando a query: 'Lula reserva valor'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.",
46
+ "answer_preview": "prediction=unpunctuated | BMU=(4, 4, 5, 0)",
47
+ "raw_response_preview": "<think>\nAnalisando a query: 'Lula reserva valor'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.\n</think>\n<plan>\nPlano de resolução:\n1. Decompor o problema em sub-tarefas\n2. Identificar ferramentas necessárias (disponíveis: som_query, buffer_stats)\n3. Executar sub-tarefas em sequência\n4. Monitorar resultados\n5. Compor resposta final\n</plan>\n<decompose>\n- Processar: Lula reserva valor\n</decompose>\n<execute>\nSub-tarefa 'Processar: Lula reserva valor' exe...",
48
+ "n_tags": 4,
49
+ "latency_ms": 3.0732154846191406
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": "unpunctuated",
58
+ "reasoning_length": 1064,
59
+ "has_think": true,
60
+ "has_plan": true,
61
+ "has_answer": true,
62
+ "has_decompose": true,
63
+ "think_preview": "Analisando a query: 'Amazonas força-tarefa vítimas'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.",
64
+ "answer_preview": "prediction=unpunctuated | BMU=(4, 4, 5, 0)",
65
+ "raw_response_preview": "<think>\nAnalisando a query: 'Amazonas força-tarefa vítimas'\nIdentificando o tipo de problema e requisitos.\nDeterminando se ferramentas são necessárias.\n</think>\n<plan>\nPlano de resolução:\n1. Decompor o problema em sub-tarefas\n2. Identificar ferramentas necessárias (disponíveis: som_query, buffer_stats)\n3. Executar sub-tarefas em sequência\n4. Monitorar resultados\n5. Compor resposta final\n</plan>\n<decompose>\n- Processar: Amazonas força-tarefa vítimas\n</decompose>\n<execute>\nSub-tarefa 'Processar: A...",
66
+ "n_tags": 4,
67
+ "latency_ms": 3.0045509338378906
68
+ }
69
+ ],
70
+ "summary": {
71
+ "n_with_answer": 3,
72
+ "n_with_think": 3,
73
+ "answer_rate": 1.0,
74
+ "think_rate": 1.0,
75
+ "avg_latency_ms": 3.060022989908854,
76
+ "avg_reasoning_length": 1030.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
+ }
xeon_runtime.py ADDED
@@ -0,0 +1,581 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ]