PowerMachine commited on
Commit
d855e28
·
verified ·
1 Parent(s): 3275441

Upload folder using huggingface_hub

Browse files
scripts/smoke_test.py ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """smoke_test.py — Smoke test do pipeline BiGRU_T_version.
3
+
4
+ Verifica:
5
+ 1. Importação de todos os módulos
6
+ 2. Criação do UnifiedModel
7
+ 3. Forward pass sem erro
8
+ 4. Backward pass sem erro
9
+ 5. QuantizedLinear funcionando (W8A8 fake quant)
10
+ 6. ModuleSelector produzindo alpha + entropy_reg
11
+ 7. apply_gradient_surgery sem erro
12
+ 8. MetaConfigurator sem erro
13
+ 9. KillSwitch detectando condições de kill
14
+ 10. Multimodal encoders importáveis
15
+
16
+ NÃO treina — apenas valida que o pipeline está íntegro.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import os
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
25
+
26
+ os.environ.setdefault("OMP_NUM_THREADS", "2")
27
+ os.environ.setdefault("MKL_NUM_THREADS", "2")
28
+
29
+ import torch
30
+ torch.set_num_threads(2)
31
+
32
+
33
+ def test_imports():
34
+ """Testa importação de todos os módulos."""
35
+ print("=== Test 1: Imports ===")
36
+ try:
37
+ from bigru_t import (
38
+ UnifiedModel, UnifiedModelConfig, create_unified_model,
39
+ u8cell_T, BiGRU4, TransformerUnit, OrqCell, TrainT, HypT,
40
+ ModuleSelector,
41
+ QuantizedLinear, quantize_tensor, apply_w8a8,
42
+ apply_gradient_surgery, orthogonalize_gradient,
43
+ MetaConfigurator,
44
+ KillSwitch, KillSwitchState,
45
+ BiGRU_T_Trainer, TrainerConfig,
46
+ )
47
+ print(" OK: all imports successful")
48
+ return True
49
+ except Exception as e:
50
+ print(f" FAIL: {e}")
51
+ import traceback; traceback.print_exc()
52
+ return False
53
+
54
+
55
+ def test_model_forward():
56
+ """Testa forward pass do UnifiedModel."""
57
+ print("\n=== Test 2: Model forward ===")
58
+ try:
59
+ from bigru_t import create_unified_model, UnifiedModelConfig
60
+ config = UnifiedModelConfig(
61
+ vocab_size=1000,
62
+ d_model=32,
63
+ max_seq_len=16,
64
+ pad_token_id=1,
65
+ max_modules=2, # pequeno para teste rápido
66
+ bigru_hidden=8,
67
+ d_transformer=16,
68
+ nhead_tu=2,
69
+ d_ff_tu=32,
70
+ output_dim_u8cell=16,
71
+ cache_len=4,
72
+ d_cache=32,
73
+ nhead_orq=2,
74
+ d_ff_orq=64,
75
+ trainT_dim=32,
76
+ nhead_train=2,
77
+ d_ff_train=64,
78
+ num_layers_train=1,
79
+ hypT_dim=32,
80
+ nhead_hyp=2,
81
+ d_ff_hyp=64,
82
+ num_layers_hyp=1,
83
+ )
84
+ model, _ = create_unified_model(config)
85
+ params = model.count_parameters()
86
+ print(f" params: {params['total']:,} ({params['total_M']:.3f}M)")
87
+
88
+ # Forward com token IDs
89
+ x = torch.randint(0, 1000, (2, 16)) # (batch=2, T=16)
90
+ y_hat, delta = model(x, temperature=1.0, use_hypothesis=False)
91
+ assert y_hat.shape == (2, 1000), f"y_hat shape {y_hat.shape} != (2, 1000)"
92
+ assert delta.shape == (2, 1000), f"delta shape {delta.shape} != (2, 1000)"
93
+ print(f" OK: forward y_hat {y_hat.shape}, delta {delta.shape}")
94
+
95
+ # Forward com hipótese
96
+ y_hat, delta = model(x, temperature=1.0, use_hypothesis=True, stop_grad_hyp=True)
97
+ assert y_hat.shape == (2, 1000)
98
+ assert delta.shape == (2, 1000)
99
+ print(f" OK: forward with hypothesis")
100
+
101
+ # Forward com return_aux
102
+ y_hat, delta, aux = model(x, temperature=1.0, use_hypothesis=False, return_aux=True)
103
+ assert "entropy_reg" in aux
104
+ assert "alpha" in aux
105
+ assert aux["alpha"].shape == (2,)
106
+ print(f" OK: return_aux entropy_reg={aux['entropy_reg'].item():.4f}, alpha={aux['alpha'].tolist()}")
107
+
108
+ return True
109
+ except Exception as e:
110
+ print(f" FAIL: {e}")
111
+ import traceback; traceback.print_exc()
112
+ return False
113
+
114
+
115
+ def test_backward():
116
+ """Testa backward pass."""
117
+ print("\n=== Test 3: Backward ===")
118
+ try:
119
+ from bigru_t import create_unified_model, UnifiedModelConfig
120
+ import torch.nn.functional as F
121
+ config = UnifiedModelConfig(
122
+ vocab_size=100, d_model=16, max_seq_len=8, pad_token_id=1,
123
+ max_modules=2, bigru_hidden=4, d_transformer=8, nhead_tu=2, d_ff_tu=16,
124
+ output_dim_u8cell=8, cache_len=4, d_cache=16, nhead_orq=2, d_ff_orq=32,
125
+ trainT_dim=16, nhead_train=2, d_ff_train=32, num_layers_train=1,
126
+ hypT_dim=16, nhead_hyp=2, d_ff_hyp=32, num_layers_hyp=1,
127
+ )
128
+ model, _ = create_unified_model(config)
129
+ x = torch.randint(0, 100, (2, 8))
130
+ target = torch.randint(0, 100, (2,))
131
+ y_hat, _ = model(x, use_hypothesis=False)
132
+ loss = F.cross_entropy(y_hat, target)
133
+ loss.backward()
134
+ # Verifica que gradientes foram computados
135
+ n_with_grad = sum(1 for p in model.parameters() if p.grad is not None and p.grad.abs().sum() > 0)
136
+ n_total = sum(1 for p in model.parameters() if p.requires_grad)
137
+ print(f" OK: backward done, loss={loss.item():.4f}, {n_with_grad}/{n_total} params have grad")
138
+ return True
139
+ except Exception as e:
140
+ print(f" FAIL: {e}")
141
+ import traceback; traceback.print_exc()
142
+ return False
143
+
144
+
145
+ def test_quantized_linear():
146
+ """Testa QuantizedLinear (Lema 3)."""
147
+ print("\n=== Test 4: QuantizedLinear (W8A8) ===")
148
+ try:
149
+ from bigru_t.quantization.quantized_linear import QuantizedLinear, quantize_tensor
150
+ # Test quantize_tensor
151
+ x = torch.randn(100)
152
+ x_q = quantize_tensor(x, num_bits=8)
153
+ err = (x - x_q).abs().max().item()
154
+ print(f" quantize_tensor max err: {err:.4f}")
155
+
156
+ # Test QuantizedLinear
157
+ ql = QuantizedLinear(10, 5)
158
+ x = torch.randn(2, 10)
159
+ y = ql(x)
160
+ assert y.shape == (2, 5)
161
+ print(f" OK: QuantizedLinear forward {y.shape}")
162
+
163
+ # Backward
164
+ y.sum().backward()
165
+ assert ql.weight.grad is not None
166
+ print(f" OK: QuantizedLinear backward, grad norm {ql.weight.grad.norm().item():.4f}")
167
+ return True
168
+ except Exception as e:
169
+ print(f" FAIL: {e}")
170
+ return False
171
+
172
+
173
+ def test_gradient_surgery():
174
+ """Testa apply_gradient_surgery (Lema 2)."""
175
+ print("\n=== Test 5: Gradient surgery ===")
176
+ try:
177
+ from bigru_t.training.gradient_surgery import orthogonalize_gradient, apply_gradient_surgery
178
+ from bigru_t import create_unified_model, UnifiedModelConfig
179
+ import torch.nn.functional as F
180
+
181
+ # Test orthogonalize_gradient — caso conflitante
182
+ g_main = torch.tensor([1.0, 0.0])
183
+ g_hyp = torch.tensor([-1.0, 0.0]) # conflitante (dot = -1 < 0)
184
+ g_orth = orthogonalize_gradient(g_main, g_hyp)
185
+ # Projeção: g_hyp - (dot/norm_sq) * g_main = (-1, 0) - (-1/1) * (1, 0) = (0, 0)
186
+ assert torch.allclose(g_orth, torch.zeros(2), atol=1e-6), f"Expected (0,0), got {g_orth}"
187
+ print(f" OK: orthogonalize conflitante → {g_orth.tolist()} (should be [0, 0])")
188
+
189
+ # Test orthogonalize_gradient — caso alinhado
190
+ g_main = torch.tensor([1.0, 0.0])
191
+ g_hyp = torch.tensor([0.5, 0.0]) # alinhado (dot = 0.5 > 0)
192
+ g_orth = orthogonalize_gradient(g_main, g_hyp)
193
+ # Sem projeção: g_hyp permanece
194
+ assert torch.allclose(g_orth, g_hyp), f"Expected {g_hyp}, got {g_orth}"
195
+ print(f" OK: orthogonalize alinhado → {g_orth.tolist()} (should be [0.5, 0.0])")
196
+
197
+ # Test apply_gradient_surgery end-to-end
198
+ config = UnifiedModelConfig(
199
+ vocab_size=50, d_model=8, max_seq_len=4, pad_token_id=1,
200
+ max_modules=2, bigru_hidden=2, d_transformer=4, nhead_tu=2, d_ff_tu=8,
201
+ output_dim_u8cell=4, cache_len=2, d_cache=8, nhead_orq=2, d_ff_orq=16,
202
+ trainT_dim=8, nhead_train=2, d_ff_train=16, num_layers_train=1,
203
+ hypT_dim=8, nhead_hyp=2, d_ff_hyp=16, num_layers_hyp=1,
204
+ )
205
+ model, _ = create_unified_model(config)
206
+ x = torch.randint(0, 50, (2, 4))
207
+ target = torch.randint(0, 50, (2,))
208
+ y_hat_main, delta = model(x, use_hypothesis=True, stop_grad_hyp=True)
209
+ loss_main = F.cross_entropy(y_hat_main, target)
210
+ loss_hyp = F.cross_entropy(y_hat_main + delta, target)
211
+ apply_gradient_surgery(model, loss_main, loss_hyp)
212
+ n_with_grad = sum(1 for p in model.parameters() if p.grad is not None)
213
+ print(f" OK: apply_gradient_surgery, {n_with_grad} params have .grad")
214
+ return True
215
+ except Exception as e:
216
+ print(f" FAIL: {e}")
217
+ import traceback; traceback.print_exc()
218
+ return False
219
+
220
+
221
+ def test_meta_configurator():
222
+ """Testa MetaConfigurator (Lema 4)."""
223
+ print("\n=== Test 6: MetaConfigurator ===")
224
+ try:
225
+ from bigru_t import create_unified_model, UnifiedModelConfig
226
+ from bigru_t.training.meta_configurator import MetaConfigurator
227
+
228
+ config = UnifiedModelConfig(
229
+ vocab_size=50, d_model=8, max_seq_len=4, pad_token_id=1,
230
+ max_modules=2, bigru_hidden=2, d_transformer=4, nhead_tu=2, d_ff_tu=8,
231
+ output_dim_u8cell=4, cache_len=2, d_cache=8, nhead_orq=2, d_ff_orq=16,
232
+ trainT_dim=8, nhead_train=2, d_ff_train=16, num_layers_train=1,
233
+ hypT_dim=8, nhead_hyp=2, d_ff_hyp=16, num_layers_hyp=1,
234
+ )
235
+ model, _ = create_unified_model(config)
236
+ meta = MetaConfigurator(model, meta_lr=0.01, sharpness_lambda=0.01)
237
+
238
+ # Initial T and tau
239
+ print(f" Initial: T={meta.temperature:.4f}, tau={meta.tau:.4f}")
240
+
241
+ # Run one meta step
242
+ x = torch.randint(0, 50, (2, 4))
243
+ target = torch.randint(0, 50, (2,))
244
+ result = meta.forward_with_meta(x, target)
245
+ print(f" After 1 step: T={result['T_new']:.4f}, tau={result['tau_new']:.4f}, "
246
+ f"loss_val={result['loss_val']:.4f}, sharpness={result['sharpness']:.4f}")
247
+
248
+ # Check tau was synced to model
249
+ assert model.tau.item() == result["tau_new"], f"model.tau {model.tau.item()} != {result['tau_new']}"
250
+ print(f" OK: MetaConfigurator synced model.tau = {model.tau.item():.4f}")
251
+ return True
252
+ except Exception as e:
253
+ print(f" FAIL: {e}")
254
+ import traceback; traceback.print_exc()
255
+ return False
256
+
257
+
258
+ def test_kill_switch():
259
+ """Testa KillSwitch."""
260
+ print("\n=== Test 7: KillSwitch ===")
261
+ try:
262
+ from bigru_t.training.kill_switch import KillSwitch
263
+ ks = KillSwitch(loss_patience=3, ram_threshold_pct=99.9, disk_min_free_gb=0.001)
264
+
265
+ # Simula 5 steps com loss não decrescente
266
+ for i in range(5):
267
+ state = ks.check(i, loss=10.0, active_modules=2)
268
+ assert state.reason is not None, "Expected kill after patience exhausted"
269
+ print(f" OK: kill triggered after {state.step} steps: {state.reason}")
270
+
271
+ # Resumo
272
+ summary = ks.summary()
273
+ print(f" OK: summary keys: {list(summary.keys())}")
274
+ return True
275
+ except Exception as e:
276
+ print(f" FAIL: {e}")
277
+ return False
278
+
279
+
280
+ def test_multimodal_imports():
281
+ """Testa importação dos encoders multimodais (reaproveitados)."""
282
+ print("\n=== Test 8: Multimodal imports ===")
283
+ try:
284
+ # Não importa os módulos diretamente (podem ter dependências pesadas)
285
+ # Apenas verifica que os arquivos existem
286
+ multimodal_dir = Path(__file__).parent.parent / "src" / "bigru_t" / "multimodal"
287
+ expected = ["text_encoder.py", "image_encoder.py", "audio_encoder.py", "video_encoder.py", "modal_router.py", "fusion_layer.py"]
288
+ for f in expected:
289
+ assert (multimodal_dir / f).exists(), f"Missing {f}"
290
+ print(f" OK: {len(expected)} multimodal modules present")
291
+ return True
292
+ except Exception as e:
293
+ print(f" FAIL: {e}")
294
+ return False
295
+
296
+
297
+ def test_utils_reused():
298
+ """Verifica que módulos utilitários reaproveitados estão presentes."""
299
+ print("\n=== Test 9: Reused utility modules ===")
300
+ try:
301
+ utils_dir = Path(__file__).parent.parent / "src" / "bigru_t" / "utils"
302
+ expected = ["hardware_detector.py", "xeon_runtime.py", "oom_guard.py", "memory_monitor.py", "tensor_ops.py", "validators.py", "logging_utils.py"]
303
+ for f in expected:
304
+ assert (utils_dir / f).exists(), f"Missing {f}"
305
+ print(f" OK: {len(expected)} utility modules present")
306
+
307
+ # Test xeon_runtime import
308
+ try:
309
+ from bigru_t.utils.xeon_runtime import optimize_xeon_environment
310
+ optimize_xeon_environment()
311
+ print(f" OK: optimize_xeon_environment() called")
312
+ except Exception as e:
313
+ print(f" WARN: xeon_runtime optimize failed: {e}")
314
+ return True
315
+ except Exception as e:
316
+ print(f" FAIL: {e}")
317
+ return False
318
+
319
+
320
+ def main():
321
+ print("=" * 60)
322
+ print("BiGRU_T_version — Smoke Test")
323
+ print("=" * 60)
324
+
325
+ tests = [
326
+ test_imports,
327
+ test_model_forward,
328
+ test_backward,
329
+ test_quantized_linear,
330
+ test_gradient_surgery,
331
+ test_meta_configurator,
332
+ test_kill_switch,
333
+ test_multimodal_imports,
334
+ test_utils_reused,
335
+ ]
336
+ results = []
337
+ for t in tests:
338
+ try:
339
+ r = t()
340
+ results.append(r)
341
+ except Exception as e:
342
+ print(f" CRASH: {e}")
343
+ results.append(False)
344
+
345
+ print("\n" + "=" * 60)
346
+ passed = sum(results)
347
+ total = len(results)
348
+ print(f"Smoke test: {passed}/{total} passed")
349
+ print("=" * 60)
350
+ sys.exit(0 if passed == total else 1)
351
+
352
+
353
+ if __name__ == "__main__":
354
+ main()
scripts/train.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """train.py — Treino de bug-detection para BiGRU_T_version (2 épocas).
3
+
4
+ Especificações do usuário atendidas:
5
+ - 2 épocas fixas (não mudar sem permissão)
6
+ - Sem dados inventados (apenas datasets do repo + HF públicos)
7
+ - Monitorar RAM, disco, loss, perplexidade
8
+ - Kill-switch: matar se loss não diminuir ou RAM explodir
9
+ - Estados temporários salvos durante treino e APAGADOS ao final
10
+ - Parâmetros do modelo aprendidos automaticamente (sem inserção manual)
11
+ - Ambiente otimizado para Xeon (AVX512, OpenMP, MKL)
12
+ - HF_TOKEN apagado ao final (se usado para datasets privados)
13
+
14
+ Uso:
15
+ export HF_TOKEN="hf_xxx" # opcional para datasets públicos
16
+ python scripts/train.py \\
17
+ --datasets CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1,Madras1/corpus-ptbr-v2 \\
18
+ --max-samples 30 \\
19
+ --epochs 2
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import logging
25
+ import os
26
+ import sys
27
+ import time
28
+ from pathlib import Path
29
+
30
+ # Adiciona src/ ao path
31
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
32
+
33
+ # Otimização Xeon (deve vir ANTES de importar torch)
34
+ os.environ.setdefault("OMP_NUM_THREADS", "2")
35
+ os.environ.setdefault("MKL_NUM_THREADS", "2")
36
+ os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
37
+ os.environ.setdefault("TORCH_NUM_THREADS", "2")
38
+
39
+ import torch
40
+ torch.set_num_threads(2)
41
+
42
+ # Tenta otimizar ambiente Xeon (do módulo reaproveitado)
43
+ try:
44
+ from bigru_t.utils.xeon_runtime import optimize_xeon_environment
45
+ optimize_xeon_environment()
46
+ except Exception as e:
47
+ logging.warning(f"Could not apply Xeon optimization: {e}")
48
+
49
+ from bigru_t import (
50
+ UnifiedModel, UnifiedModelConfig, create_unified_model,
51
+ BiGRU_T_Trainer, TrainerConfig,
52
+ )
53
+ from bigru_t.data.streaming_datasets import stream_dataset
54
+
55
+ logging.basicConfig(
56
+ level=logging.INFO,
57
+ format="%(asctime)s [%(levelname)s] %(message)s",
58
+ datefmt="%H:%M:%S",
59
+ handlers=[logging.StreamHandler()],
60
+ )
61
+ logger = logging.getLogger(__name__)
62
+
63
+
64
+ def load_tokenizer(path: str):
65
+ """Carrega tokenizer BBPE 16K."""
66
+ from tokenizers import Tokenizer
67
+ return Tokenizer.from_file(path)
68
+
69
+
70
+ def load_samples(
71
+ datasets: str,
72
+ max_samples_per_dataset: int,
73
+ hf_token: str | None,
74
+ ) -> list:
75
+ """Carrega amostras via streaming (reaproveita streaming_datasets_v13_9)."""
76
+ samples = []
77
+ datasets_list = [d.strip() for d in datasets.split(",") if d.strip()]
78
+ logger.info(f"Loading samples from {len(datasets_list)} datasets...")
79
+ for ds_name in datasets_list:
80
+ ds_start = time.time()
81
+ ds_count = 0
82
+ try:
83
+ for sample in stream_dataset(
84
+ ds_name,
85
+ max_samples=max_samples_per_dataset,
86
+ hf_token=hf_token,
87
+ ):
88
+ samples.append(sample)
89
+ ds_count += 1
90
+ if ds_count >= max_samples_per_dataset:
91
+ break
92
+ if time.time() - ds_start > 300:
93
+ logger.warning(f" timeout em {ds_name} após {ds_count} amostras")
94
+ break
95
+ except Exception as e:
96
+ logger.error(f"Erro carregando {ds_name}: {e}")
97
+ continue
98
+ logger.info(f" {ds_name}: {ds_count} amostras em {time.time()-ds_start:.1f}s")
99
+ return samples
100
+
101
+
102
+ def main():
103
+ parser = argparse.ArgumentParser(description="BiGRU_T_version — Bug-detection training (2 epochs)")
104
+ parser.add_argument(
105
+ "--datasets",
106
+ type=str,
107
+ default="CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1,Madras1/corpus-ptbr-v2,dominguesm/restore-punctuation-ptbr-dataset",
108
+ help="Lista separada por vírgulas de datasets HF",
109
+ )
110
+ parser.add_argument("--max-samples", type=int, default=30, help="Amostras POR dataset (default 30)")
111
+ parser.add_argument("--epochs", type=int, default=2, help="Nº de épocas (default 2)")
112
+ parser.add_argument("--batch-size", type=int, default=1)
113
+ parser.add_argument("--grad-accum", type=int, default=4)
114
+ parser.add_argument("--lr", type=float, default=1e-3)
115
+ parser.add_argument("--max-seq-len", type=int, default=64)
116
+ parser.add_argument("--output-dir", type=str, default="/home/z/my-project/BiGRU_T_version/model_final")
117
+ parser.add_argument("--temp-dir", type=str, default="/home/z/my-project/BiGRU_T_version/_temp_checkpoints")
118
+ parser.add_argument(
119
+ "--tokenizer-path",
120
+ type=str,
121
+ default="/home/z/my-project/source/model_final/tokenizer/tokenizer.json",
122
+ )
123
+ parser.add_argument("--no-hypothesis", action="store_true", help="Desativar hipótese (Lema 3)")
124
+ parser.add_argument("--keep-temp", action="store_true", help="Manter checkpoints temporários")
125
+ parser.add_argument("--smoke-test", action="store_true", help="Smoke test: 5 samples, 1 epoch")
126
+ args = parser.parse_args()
127
+
128
+ if args.smoke_test:
129
+ logger.info("SMOKE TEST MODE — 5 samples/dataset, 1 epoch")
130
+ args.max_samples = 5
131
+ args.epochs = 1
132
+ args.grad_accum = 2
133
+ args.datasets = "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1"
134
+
135
+ # HF token (opcional para datasets públicos)
136
+ hf_token = os.environ.get("HF_TOKEN") or None
137
+
138
+ # Configuração do modelo
139
+ model_config = UnifiedModelConfig(
140
+ vocab_size=16384,
141
+ d_model=128,
142
+ max_seq_len=args.max_seq_len,
143
+ # input_dim é automaticamente = d_model via __post_init__
144
+ # Para bug-detection, reduzimos max_modules (64 é caro)
145
+ max_modules=8, # 8 módulos em vez de 64
146
+ bigru_hidden=32,
147
+ d_transformer=64,
148
+ nhead_tu=4,
149
+ d_ff_tu=128,
150
+ output_dim_u8cell=64,
151
+ cache_len=16,
152
+ d_cache=128,
153
+ nhead_orq=8,
154
+ d_ff_orq=256,
155
+ trainT_dim=128,
156
+ nhead_train=4,
157
+ d_ff_train=256,
158
+ num_layers_train=2,
159
+ hypT_dim=128,
160
+ nhead_hyp=4,
161
+ d_ff_hyp=256,
162
+ num_layers_hyp=2,
163
+ num_bits=8,
164
+ dropout=0.1,
165
+ )
166
+
167
+ # Cria modelo
168
+ logger.info("Criando UnifiedModel...")
169
+ model, _ = create_unified_model(model_config)
170
+ params = model.count_parameters()
171
+ logger.info(f" params: {params['total']:,} ({params['total_M']:.2f}M)")
172
+
173
+ # Carrega tokenizer
174
+ tokenizer = load_tokenizer(args.tokenizer_path)
175
+
176
+ # Carrega datasets
177
+ samples = load_samples(args.datasets, args.max_samples, hf_token)
178
+ n = len(samples)
179
+ if n == 0:
180
+ logger.error("Nenhuma amostra carregada — abortando")
181
+ sys.exit(1)
182
+ logger.info(f"Total: {n} amostras carregadas")
183
+
184
+ # Split 90/10 treino/val
185
+ import random
186
+ random.seed(42)
187
+ random.shuffle(samples)
188
+ split = max(1, int(0.9 * n))
189
+ train_samples = samples[:split]
190
+ val_samples = samples[split:] or samples[:1] # fallback: 1 amostra
191
+ logger.info(f" train: {len(train_samples)} | val: {len(val_samples)}")
192
+
193
+ # Configuração do trainer
194
+ trainer_config = TrainerConfig(
195
+ epochs=args.epochs,
196
+ datasets=args.datasets,
197
+ max_samples_per_dataset=args.max_samples,
198
+ max_seq_len=args.max_seq_len,
199
+ per_device_batch_size=args.batch_size,
200
+ grad_accum=args.grad_accum,
201
+ lr=args.lr,
202
+ use_hypothesis=not args.no_hypothesis,
203
+ output_dir=args.output_dir,
204
+ temp_dir=args.temp_dir,
205
+ keep_temp=args.keep_temp,
206
+ )
207
+
208
+ # Trainer
209
+ trainer = BiGRU_T_Trainer(
210
+ model=model,
211
+ tokenizer=tokenizer,
212
+ config=trainer_config,
213
+ train_samples=train_samples,
214
+ val_samples=val_samples,
215
+ )
216
+
217
+ # Treina
218
+ result = trainer.train()
219
+
220
+ # Print resultado
221
+ import json
222
+ print("\n=== Resultado Final ===")
223
+ print(json.dumps(result, indent=2, default=str))
224
+
225
+ # Apaga HF token do ambiente (especificação do usuário)
226
+ if "HF_TOKEN" in os.environ:
227
+ del os.environ["HF_TOKEN"]
228
+ logger.info("HF_TOKEN apagado do ambiente")
229
+
230
+ # Exit code: 0 se OK, 1 se morto pelo kill-switch
231
+ sys.exit(0 if not result.get("killed") else 1)
232
+
233
+
234
+ if __name__ == "__main__":
235
+ main()
scripts/train_fast.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """train_fast.py — Treino rápido de bug-detection (2 épocas, modelo pequeno).
3
+
4
+ Versão otimizada para rodar em < 5 minutos no ambiente Xeon 2-core:
5
+ - max_modules=4 (em vez de 8)
6
+ - bigru_hidden=16 (em vez de 32)
7
+ - d_transformer=32 (em vez de 64)
8
+ - num_layers_train=1, num_layers_hyp=1
9
+ - max_samples=8 por dataset
10
+ - 1 dataset (CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1)
11
+
12
+ Valida todos os 4 lemas sem pretender produzir modelo SOTA.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import sys
18
+ import time
19
+ import json
20
+ import logging
21
+ from pathlib import Path
22
+
23
+ # Adiciona src/ ao path
24
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
25
+
26
+ # Otimização Xeon
27
+ os.environ.setdefault("OMP_NUM_THREADS", "2")
28
+ os.environ.setdefault("MKL_NUM_THREADS", "2")
29
+ os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
30
+
31
+ import torch
32
+ torch.set_num_threads(2)
33
+
34
+ try:
35
+ from bigru_t.utils.xeon_runtime import optimize_xeon_environment
36
+ optimize_xeon_environment()
37
+ except Exception as e:
38
+ logging.warning(f"Could not apply Xeon optimization: {e}")
39
+
40
+ from bigru_t import (
41
+ UnifiedModel, UnifiedModelConfig, create_unified_model,
42
+ BiGRU_T_Trainer, TrainerConfig,
43
+ )
44
+ from bigru_t.data.streaming_datasets import stream_dataset
45
+
46
+ logging.basicConfig(
47
+ level=logging.INFO,
48
+ format="%(asctime)s [%(levelname)s] %(message)s",
49
+ datefmt="%H:%M:%S",
50
+ handlers=[logging.StreamHandler()],
51
+ )
52
+ logger = logging.getLogger(__name__)
53
+
54
+
55
+ def main():
56
+ # HF token
57
+ hf_token = os.environ.get("HF_TOKEN") or None
58
+
59
+ # Modelo pequeno para bug-detection rápido
60
+ model_config = UnifiedModelConfig(
61
+ vocab_size=16384,
62
+ d_model=64,
63
+ max_seq_len=32,
64
+ pad_token_id=1,
65
+ max_modules=4, # 4 módulos em vez de 8
66
+ bigru_hidden=16, # 16 em vez de 32
67
+ d_transformer=32, # 32 em vez de 64
68
+ nhead_tu=2, # 2 em vez de 4 (32/2=16 ok)
69
+ d_ff_tu=64, # 64 em vez de 128
70
+ output_dim_u8cell=32, # 32 em vez de 64
71
+ cache_len=8, # 8 em vez de 16
72
+ d_cache=64, # 64 em vez de 128
73
+ nhead_orq=2, # 2 em vez de 8 (64/2=32 ok)
74
+ d_ff_orq=128, # 128 em vez de 256
75
+ trainT_dim=64,
76
+ nhead_train=2,
77
+ d_ff_train=128,
78
+ num_layers_train=1, # 1 em vez de 2
79
+ hypT_dim=64,
80
+ nhead_hyp=2,
81
+ d_ff_hyp=128,
82
+ num_layers_hyp=1, # 1 em vez de 2
83
+ num_bits=8,
84
+ dropout=0.1,
85
+ )
86
+
87
+ logger.info("Criando UnifiedModel (small config)...")
88
+ model, _ = create_unified_model(model_config)
89
+ params = model.count_parameters()
90
+ logger.info(f" params: {params['total']:,} ({params['total_M']:.2f}M)")
91
+
92
+ # Tokenizer
93
+ from tokenizers import Tokenizer
94
+ tok_path = "/home/z/my-project/source/model_final/tokenizer/tokenizer.json"
95
+ tokenizer = Tokenizer.from_file(tok_path)
96
+
97
+ # Carrega 1 dataset
98
+ ds_name = "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1"
99
+ max_samples = 8
100
+ logger.info(f"Loading {max_samples} samples from {ds_name}...")
101
+ samples = []
102
+ t0 = time.time()
103
+ for sample in stream_dataset(ds_name, max_samples=max_samples, hf_token=hf_token):
104
+ samples.append(sample)
105
+ if len(samples) >= max_samples:
106
+ break
107
+ if time.time() - t0 > 120:
108
+ logger.warning(f"Timeout após {len(samples)} amostras")
109
+ break
110
+ logger.info(f"Loaded {len(samples)} samples in {time.time()-t0:.1f}s")
111
+
112
+ if not samples:
113
+ logger.error("Nenhuma amostra carregada")
114
+ sys.exit(1)
115
+
116
+ # Split 90/10
117
+ import random
118
+ random.seed(42)
119
+ random.shuffle(samples)
120
+ split = max(1, int(0.9 * len(samples)))
121
+ train_samples = samples[:split]
122
+ val_samples = samples[split:] or samples[:1]
123
+ logger.info(f" train: {len(train_samples)} | val: {len(val_samples)}")
124
+
125
+ # Trainer config
126
+ trainer_config = TrainerConfig(
127
+ epochs=2,
128
+ datasets=ds_name,
129
+ max_samples_per_dataset=max_samples,
130
+ max_seq_len=32,
131
+ per_device_batch_size=1,
132
+ grad_accum=2,
133
+ lr=1e-3,
134
+ use_hypothesis=True,
135
+ meta_interval=5,
136
+ log_every=1,
137
+ save_temp_every=100, # não salvar temp (modelo pequeno)
138
+ output_dir="/home/z/my-project/BiGRU_T_version/model_final",
139
+ temp_dir="/home/z/my-project/BiGRU_T_version/_temp_checkpoints",
140
+ keep_temp=False,
141
+ )
142
+
143
+ trainer = BiGRU_T_Trainer(
144
+ model=model,
145
+ tokenizer=tokenizer,
146
+ config=trainer_config,
147
+ train_samples=train_samples,
148
+ val_samples=val_samples,
149
+ )
150
+
151
+ result = trainer.train()
152
+
153
+ print("\n=== Resultado Final ===")
154
+ print(json.dumps(result, indent=2, default=str))
155
+
156
+ # Apaga HF token
157
+ if "HF_TOKEN" in os.environ:
158
+ del os.environ["HF_TOKEN"]
159
+ logger.info("HF_TOKEN apagado do ambiente")
160
+
161
+ sys.exit(0 if not result.get("killed") else 1)
162
+
163
+
164
+ if __name__ == "__main__":
165
+ main()
scripts/upload_to_hf.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """upload_to_hf.py — Upload do BiGRU_T_version para HuggingFace Hub.
3
+
4
+ Faz upload de:
5
+ - model_final/pytorch_model.bin
6
+ - model_final/config.json
7
+ - model_final/tokenizer/tokenizer.json
8
+ - training_report.json
9
+ - README.md
10
+ - src/ (código fonte)
11
+ - scripts/ (scripts de treino/smoke test)
12
+ - docs/ (análise matemática)
13
+
14
+ Repositório destino: PowerMachine/BiGRU_T_version (public)
15
+
16
+ Uso:
17
+ export HF_TOKEN="hf_xxx"
18
+ python scripts/upload_to_hf.py
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ import sys
24
+ from pathlib import Path
25
+
26
+ from huggingface_hub import HfApi, create_repo
27
+
28
+
29
+ def main():
30
+ token = os.environ.get("HF_TOKEN")
31
+ if not token:
32
+ print("ERROR: HF_TOKEN not set")
33
+ sys.exit(1)
34
+
35
+ repo_id = "PowerMachine/BiGRU_T_version"
36
+ project_dir = Path("/home/z/my-project/BiGRU_T_version")
37
+
38
+ print(f"Uploading to {repo_id} (public)...")
39
+
40
+ api = HfApi(token=token)
41
+
42
+ # Cria repo (idempotente)
43
+ try:
44
+ create_repo(repo_id, repo_type="model", token=token, private=False, exist_ok=True)
45
+ print(f" Repo created/exists: {repo_id}")
46
+ except Exception as e:
47
+ print(f" Warning creating repo: {e}")
48
+
49
+ # Upload de arquivos individuais
50
+ files_to_upload = [
51
+ ("README.md", "README.md"),
52
+ ("requirements.txt", "requirements.txt"),
53
+ ("training_report.json", "training_report.json"),
54
+ ("model_final/config.json", "config.json"),
55
+ ("model_final/pytorch_model.bin", "pytorch_model.bin"),
56
+ ("model_final/tokenizer/tokenizer.json", "tokenizer/tokenizer.json"),
57
+ ("docs/analysis.md", "docs/analysis.md"),
58
+ ]
59
+
60
+ for src, dst in files_to_upload:
61
+ src_path = project_dir / src
62
+ if not src_path.exists():
63
+ print(f" SKIP (not found): {src}")
64
+ continue
65
+ print(f" Uploading {src} → {dst}...")
66
+ try:
67
+ api.upload_file(
68
+ path_or_fileobj=str(src_path),
69
+ path_in_repo=dst,
70
+ repo_id=repo_id,
71
+ repo_type="model",
72
+ token=token,
73
+ )
74
+ print(f" OK")
75
+ except Exception as e:
76
+ print(f" FAIL: {e}")
77
+
78
+ # Upload de diretórios como pastas
79
+ dirs_to_upload = [
80
+ ("src", "src"),
81
+ ("scripts", "scripts"),
82
+ ]
83
+
84
+ for src_dir, dst_dir in dirs_to_upload:
85
+ src_path = project_dir / src_dir
86
+ if not src_path.exists():
87
+ print(f" SKIP (not found): {src_dir}/")
88
+ continue
89
+ print(f" Uploading {src_dir}/ → {dst_dir}/ ...")
90
+ try:
91
+ api.upload_folder(
92
+ folder_path=str(src_path),
93
+ path_in_repo=dst_dir,
94
+ repo_id=repo_id,
95
+ repo_type="model",
96
+ token=token,
97
+ ignore_patterns=["__pycache__", "*.pyc", ".pytest_cache", "_temp_checkpoints"],
98
+ )
99
+ print(f" OK")
100
+ except Exception as e:
101
+ print(f" FAIL: {e}")
102
+
103
+ print(f"\nUpload complete: https://huggingface.co/{repo_id}")
104
+
105
+ # Apaga token do ambiente (especificação do usuário)
106
+ del os.environ["HF_TOKEN"]
107
+ print("HF_TOKEN apagado do ambiente")
108
+
109
+
110
+ if __name__ == "__main__":
111
+ main()