PowerMachine commited on
Commit
a7ad9e5
·
verified ·
1 Parent(s): 515668f

Upload cnn_bigru/tests/test_50_samples.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. cnn_bigru/tests/test_50_samples.py +513 -0
cnn_bigru/tests/test_50_samples.py ADDED
@@ -0,0 +1,513 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """test_50_samples.py — Teste de 50 amostras para erros lógicos ou falhas.
2
+
3
+ Executa o pipeline completo:
4
+ 1. Inicializa xeon_runtime + memory_optimizer
5
+ 2. Treina BBPE tokenizer em corpus sintético
6
+ 3. Cria dataset streaming multimodal (50 amostras)
7
+ 4. Instancia modelo multimodal + generator + verifier + anti-hallucination
8
+ 5. Executa treinamento cooperativo com:
9
+ - Synergy search (N tentativas)
10
+ - Hypothesis controller (ativa em punições)
11
+ - Auto-learner (ajuste dinâmico de LR + spectral norm)
12
+ 6. Executa inferência com sampling
13
+ 7. Avalia perplexidade
14
+ 8. Reporta erros lógicos/falhas encontradas
15
+
16
+ Usage:
17
+ python -m cnn_bigru.tests.test_50_samples
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ import os
23
+ import sys
24
+ import time
25
+ import traceback
26
+ from pathlib import Path
27
+ from typing import Dict, List
28
+
29
+ # Setup paths (must come before torch import for xeon_runtime)
30
+ PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
31
+ sys.path.insert(0, str(PROJECT_ROOT))
32
+
33
+ # Ativa Xeon runtime ANTES de importar torch
34
+ from cnn_bigru.utils.xeon_runtime import optimize_xeon_environment
35
+ N_CORES = optimize_xeon_environment()
36
+
37
+ import numpy as np
38
+ import torch
39
+ from torch.utils.data import DataLoader
40
+
41
+ from cnn_bigru.tokenizer.bbpe_tokenizer import BBPETokenizer
42
+ from cnn_bigru.data.streaming_dataset import (
43
+ MultimodalStreamingDataset,
44
+ collate_multimodal,
45
+ )
46
+ from cnn_bigru.models.multimodal_model import MultimodalCNNBiGRU
47
+ from cnn_bigru.models.generator_verifier import (
48
+ GeneratorCNNBiGRU,
49
+ VerifierCNNBiGRU,
50
+ AntiHallucinationLayer,
51
+ )
52
+ from cnn_bigru.losses.losses import LossConfig, MultiLoss
53
+ from cnn_bigru.training.trainer import TrainerConfig, CooperativeTrainer
54
+ from cnn_bigru.training.auto_learner import (
55
+ AutoLearnConfig,
56
+ orthogonal_init_model,
57
+ )
58
+ from cnn_bigru.training.hypothesis_controller import (
59
+ HypothesisConfig,
60
+ HypothesisController,
61
+ )
62
+ from cnn_bigru.inference.inference import (
63
+ generate_with_sampling,
64
+ evaluate_perplexity,
65
+ )
66
+ from cnn_bigru.utils.memory_optimizer import MemoryOptimizer
67
+
68
+ logging.basicConfig(
69
+ level=logging.INFO,
70
+ format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
71
+ datefmt="%H:%M:%S",
72
+ )
73
+ logger = logging.getLogger("test_50")
74
+
75
+
76
+ # ============================================================================
77
+ # Corpus para treino do tokenizer
78
+ # ============================================================================
79
+
80
+ CORPUS_TEXTS = [
81
+ "o modelo cooperativo cnn-bigru combina fluxos paralelos",
82
+ "a atencao cruzada troca informacoes entre redes a e b",
83
+ "gru bidirecional captura dependencias temporais em ambas direcoes",
84
+ "a porta de atenuacao controla o fluxo de informacao entre celulas",
85
+ "a camada anti-alucinacao usa logica fuzzy de lukasiewicz",
86
+ "o verificador classifica passos com sigmoid binaria",
87
+ "penalidades linear e exponencial reduzem o erro grave",
88
+ "ajuste dinamico de lr estabiliza o treinamento cooperativo",
89
+ "normalizacao espectral limita a norma dos pesos",
90
+ "inicializacao ortogonal estabiliza matrizes recorrentes",
91
+ "o gerador decodificador usa atencao bahdanau sobre o encoder",
92
+ "a fusao multimodal combina texto imagem e audio",
93
+ "hipoteses sao ativadas quando o verificador pune o passo",
94
+ "synergy search tenta n configuracoes e escolhe a melhor",
95
+ "a perplexidade mede a confusao do modelo na previsao",
96
+ "top-k e top-p filtram a distribuicao de probabilidade",
97
+ "temperature ajusta a entropia das previsoes do modelo",
98
+ "presence penalty pune tokens ja aparecidos na geracao",
99
+ "frequency penalty pune proporcionalmente a frequencia do token",
100
+ "streaming dataset carrega amostras sem materializacao completa",
101
+ "byte bpe tokeniza qualquer string utf-8 sem unk",
102
+ "o otimizador adamw combina momentum e weight decay",
103
+ "gradient clipping previne explosao de gradiente",
104
+ "amp reduz vram com precisao mista bfloat16",
105
+ "memory optimizer limpa cache entre batches",
106
+ ] * 4 # ~100 amostras para treino BBPE
107
+
108
+
109
+ def step_01_init_runtime() -> Dict:
110
+ """Inicializa runtime e reporta configurações."""
111
+ logger.info("=" * 70)
112
+ logger.info("PASSO 1: Inicialização do runtime Xeon + memory optimizer")
113
+ logger.info("=" * 70)
114
+ from cnn_bigru.utils.xeon_runtime import get_runtime_info
115
+ info = get_runtime_info()
116
+ for k, v in info.items():
117
+ logger.info(" %s: %s", k, v)
118
+ mem = MemoryOptimizer(enable_amp=False)
119
+ mem.configure()
120
+ mem_info = mem.get_memory_mb()
121
+ logger.info(" Memória: %s", mem_info)
122
+ return {"runtime": info, "memory": mem_info}
123
+
124
+
125
+ def step_02_train_tokenizer() -> BBPETokenizer:
126
+ """Treina BBPE tokenizer em corpus sintético."""
127
+ logger.info("=" * 70)
128
+ logger.info("PASSO 2: Treino do BBPE tokenizer")
129
+ logger.info("=" * 70)
130
+ t0 = time.time()
131
+ tok = BBPETokenizer.train_from_texts(
132
+ CORPUS_TEXTS,
133
+ vocab_size=2000,
134
+ min_frequency=1,
135
+ )
136
+ elapsed = time.time() - t0
137
+ logger.info(" Vocab size: %d", tok.vocab_size)
138
+ logger.info(" BOS/PAD/EOS IDs: %d/%d/%d", tok.bos_id, tok.pad_id, tok.eos_id)
139
+ logger.info(" Tempo: %.2fs", elapsed)
140
+
141
+ # Validação roundtrip
142
+ test_strs = CORPUS_TEXTS[:5]
143
+ roundtrip = tok.validate_roundtrip(test_strs)
144
+ logger.info(" Roundtrip accuracy: %.2f%%", roundtrip * 100)
145
+
146
+ if roundtrip < 0.8:
147
+ logger.warning(" Roundtrip baixo — possível problema no tokenizer")
148
+ return tok, roundtrip
149
+
150
+
151
+ def step_03_create_dataset(tokenizer: BBPETokenizer, n_samples: int = 50) -> DataLoader:
152
+ """Cria dataset streaming multimodal com N amostras."""
153
+ logger.info("=" * 70)
154
+ logger.info("PASSO 3: Criação do dataset streaming multimodal (%d amostras)", n_samples)
155
+ logger.info("=" * 70)
156
+
157
+ # Para teste determinístico, usamos fallback sintético
158
+ dataset = MultimodalStreamingDataset(
159
+ n_samples=n_samples,
160
+ hf_datasets=[], # skip HF forçando sintético
161
+ use_synthetic_fallback=True,
162
+ seed=42,
163
+ image_size=(28, 28, 1),
164
+ audio_shape=(32, 40),
165
+ )
166
+
167
+ # Coleta todas as amostras em uma lista (para DataLoader iterável)
168
+ samples = list(dataset)
169
+ logger.info(" Amostras coletadas: %d", len(samples))
170
+ assert len(samples) == n_samples, f"Esperado {n_samples}, obtido {len(samples)}"
171
+
172
+ # Cria DataLoader com collate_fn
173
+ from torch.utils.data import DataLoader
174
+ loader = DataLoader(
175
+ samples,
176
+ batch_size=8,
177
+ shuffle=False,
178
+ collate_fn=lambda b: collate_multimodal(b, tokenizer, max_len=32),
179
+ )
180
+ logger.info(" DataLoader criado: batch_size=8, max_len=32")
181
+ return loader
182
+
183
+
184
+ def step_04_init_model(tokenizer: BBPETokenizer, device: str = "cpu") -> Dict:
185
+ """Instancia todos os componentes do modelo."""
186
+ logger.info("=" * 70)
187
+ logger.info("PASSO 4: Instanciação dos modelos")
188
+ logger.info("=" * 70)
189
+ V = tokenizer.vocab_size
190
+
191
+ # Modelo multimodal principal
192
+ model = MultimodalCNNBiGRU(
193
+ vocab_size=V,
194
+ num_classes=3,
195
+ embedding_dim=32,
196
+ cnn_filters=32,
197
+ gru_hidden=32,
198
+ n_heads=4,
199
+ dropout=0.1,
200
+ pad_idx=tokenizer.pad_id,
201
+ img_channels=1,
202
+ img_hidden=16,
203
+ img_out_dim=32,
204
+ audio_freq=40,
205
+ audio_hidden=16,
206
+ audio_out_dim=32,
207
+ fusion_dim=64,
208
+ use_spectral_norm=False,
209
+ )
210
+
211
+ # Aplica inicialização ortogonal
212
+ n_init = orthogonal_init_model(model)
213
+ logger.info(" Modelo multimodal: %d params, %d camadas ortogonalizadas",
214
+ sum(p.numel() for p in model.parameters()), n_init)
215
+
216
+ # Generator (encoder + decoder)
217
+ generator = GeneratorCNNBiGRU(
218
+ vocab_size=V,
219
+ embedding_dim=32,
220
+ cnn_filters=32,
221
+ gru_hidden=32,
222
+ n_heads=4,
223
+ dropout=0.1,
224
+ pad_idx=tokenizer.pad_id,
225
+ max_proof_len=16,
226
+ )
227
+ orthogonal_init_model(generator)
228
+
229
+ # Verifier
230
+ verifier = VerifierCNNBiGRU(
231
+ vocab_size=V,
232
+ embedding_dim=32,
233
+ cnn_filters=32,
234
+ gru_hidden=32,
235
+ n_heads=4,
236
+ dropout=0.1,
237
+ pad_idx=tokenizer.pad_id,
238
+ )
239
+ orthogonal_init_model(verifier)
240
+
241
+ # Anti-hallucination
242
+ anti_hall = AntiHallucinationLayer(vocab_size=V, embed_dim=16)
243
+
244
+ logger.info(" Generator params: %d", sum(p.numel() for p in generator.parameters()))
245
+ logger.info(" Verifier params: %d", sum(p.numel() for p in verifier.parameters()))
246
+ logger.info(" Anti-hall params: %d", sum(p.numel() for p in anti_hall.parameters()))
247
+
248
+ return {
249
+ "model": model,
250
+ "generator": generator,
251
+ "verifier": verifier,
252
+ "anti_hall": anti_hall,
253
+ }
254
+
255
+
256
+ def step_05_train(
257
+ models: Dict,
258
+ tokenizer: BBPETokenizer,
259
+ dataloader: DataLoader,
260
+ device: str = "cpu",
261
+ ) -> Dict:
262
+ """Executa treinamento cooperativo."""
263
+ logger.info("=" * 70)
264
+ logger.info("PASSO 5: Treinamento cooperativo (synergy + hipóteses + auto-learn)")
265
+ logger.info("=" * 70)
266
+
267
+ cfg = TrainerConfig(
268
+ num_epochs=2,
269
+ max_batches_per_epoch=6,
270
+ batch_size=8,
271
+ n_synergy_attempts=3,
272
+ use_synergy_search=True,
273
+ use_hypotheses=True,
274
+ n_hypotheses=4,
275
+ loss_config=LossConfig(
276
+ alpha=1.0, beta=0.5, gamma_loss=0.3, delta=0.01,
277
+ lambda_penal=0.1, mu_exp_penal=0.05,
278
+ gamma_exp=1.0, threshold_err=0.5,
279
+ l2_reg=1e-5, use_curvature=True, curvature_eps=1e-3,
280
+ ),
281
+ auto_config=AutoLearnConfig(
282
+ kappa_curv=0.01, grad_clip=1.0, spectral_radius=1.0,
283
+ lr_min=1e-6, lr_max=1e-2,
284
+ initial_lr_G=1e-3, initial_lr_V=1e-3,
285
+ use_spectral_norm=True, apply_after_step=True,
286
+ ),
287
+ device=device,
288
+ log_every=1,
289
+ )
290
+
291
+ trainer = CooperativeTrainer(
292
+ model=models["model"],
293
+ tokenizer=tokenizer,
294
+ config=cfg,
295
+ generator=models["generator"],
296
+ verifier=models["verifier"],
297
+ anti_hallucination=models["anti_hall"],
298
+ )
299
+
300
+ try:
301
+ result = trainer.train(dataloader)
302
+ logger.info(" Treinamento OK | final_loss=%.4f | final_ppl=%.2f | elapsed=%.1fs",
303
+ result["final_loss"], result["final_ppl"], result["elapsed_s"])
304
+ return result
305
+ except Exception as e:
306
+ logger.error(" Treinamento FALHOU: %s", e)
307
+ logger.error(traceback.format_exc())
308
+ raise
309
+
310
+
311
+ def step_06_inference(
312
+ model: MultimodalCNNBiGRU,
313
+ tokenizer: BBPETokenizer,
314
+ device: str = "cpu",
315
+ ) -> Dict:
316
+ """Executa inferência com sampling."""
317
+ logger.info("=" * 70)
318
+ logger.info("PASSO 6: Inferência com Temperatura + Top-K + Top-P + Penalidades")
319
+ logger.info("=" * 70)
320
+
321
+ prompts = [
322
+ ("o modelo coopera entre", "fluxos paralelos"),
323
+ ("atencao cruzada troca", "informacoes entre redes"),
324
+ ("gru bidirecional captura", "dependencias temporais"),
325
+ ]
326
+
327
+ results = []
328
+ for prompt_a, prompt_b in prompts:
329
+ try:
330
+ result = generate_with_sampling(
331
+ model=model,
332
+ tokenizer=tokenizer,
333
+ prompt_a=prompt_a,
334
+ prompt_b=prompt_b,
335
+ max_new_tokens=16,
336
+ temperature=0.7,
337
+ top_k=20,
338
+ top_p=0.9,
339
+ presence_penalty=0.3,
340
+ frequency_penalty=0.3,
341
+ device=device,
342
+ )
343
+ logger.info(" Prompt A: %s", prompt_a)
344
+ logger.info(" Prompt B: %s", prompt_b)
345
+ logger.info(" Gerado: %s", result["text"][:100])
346
+ logger.info(" Metrics: %s", result["metrics"])
347
+ results.append({"prompt_a": prompt_a, "prompt_b": prompt_b, **result})
348
+ except Exception as e:
349
+ logger.error(" Inferência falhou para (%s, %s): %s", prompt_a, prompt_b, e)
350
+ results.append({"prompt_a": prompt_a, "prompt_b": prompt_b, "error": str(e)})
351
+
352
+ return {"results": results}
353
+
354
+
355
+ def step_07_eval_ppl(
356
+ model: MultimodalCNNBiGRU,
357
+ tokenizer: BBPETokenizer,
358
+ dataloader: DataLoader,
359
+ device: str = "cpu",
360
+ ) -> Dict:
361
+ """Avalia perplexidade."""
362
+ logger.info("=" * 70)
363
+ logger.info("PASSO 7: Avaliação de Perplexidade (PPL)")
364
+ logger.info("=" * 70)
365
+ try:
366
+ result = evaluate_perplexity(
367
+ model=model,
368
+ dataloader=dataloader,
369
+ tokenizer=tokenizer,
370
+ device=device,
371
+ max_batches=5,
372
+ )
373
+ logger.info(" Loss: %.4f | PPL: %.2f | batches: %d",
374
+ result["loss"], result["ppl"], result["n_batches"])
375
+ return result
376
+ except Exception as e:
377
+ logger.error(" PPL falhou: %s", e)
378
+ logger.error(traceback.format_exc())
379
+ return {"error": str(e)}
380
+
381
+
382
+ def step_08_report_errors(errors: List[str], warnings: List[str]) -> None:
383
+ """Reporta erros lógicos ou falhas encontradas."""
384
+ logger.info("=" * 70)
385
+ logger.info("PASSO 8: Relatório de erros lógicos ou falhas")
386
+ logger.info("=" * 70)
387
+
388
+ if not errors:
389
+ logger.info(" ✓ NENHUM ERRO CRÍTICO encontrado")
390
+ else:
391
+ logger.error(" ✗ %d ERRO(S) CRÍTICO(S) encontrado(s):", len(errors))
392
+ for e in errors:
393
+ logger.error(" - %s", e)
394
+
395
+ if not warnings:
396
+ logger.info(" ✓ Nenhum warning relevante")
397
+ else:
398
+ logger.warning(" ⚠ %d warning(s):", len(warnings))
399
+ for w in warnings:
400
+ logger.warning(" - %s", w)
401
+
402
+ logger.info("=" * 70)
403
+
404
+
405
+ def main():
406
+ """Executa o teste completo de 50 amostras."""
407
+ logger.info("INICIANDO TESTE DE 50 AMOSTRAS — CNN-BiGRU MULTIMODAL COOPERATIVO")
408
+ logger.info("Project root: %s", PROJECT_ROOT)
409
+ logger.info("Device: %s", "cpu")
410
+ logger.info("Cores: %d", N_CORES)
411
+
412
+ errors: List[str] = []
413
+ warnings: List[str] = []
414
+
415
+ try:
416
+ # Step 1
417
+ step_01_init_runtime()
418
+
419
+ # Step 2
420
+ tokenizer, roundtrip = step_02_train_tokenizer()
421
+ if roundtrip < 0.8:
422
+ warnings.append(f"BBPE roundtrip accuracy = {roundtrip:.2%} (esperado >= 80%)")
423
+
424
+ # Step 3
425
+ dataloader = step_03_create_dataset(tokenizer, n_samples=50)
426
+
427
+ # Step 4
428
+ models = step_04_init_model(tokenizer, device="cpu")
429
+
430
+ # Verificação: forward pass simples antes do treino
431
+ try:
432
+ batch = next(iter(dataloader))
433
+ with torch.no_grad():
434
+ out = models["model"](
435
+ batch["input_ids_a"], batch["input_ids_b"],
436
+ images=batch["images"], audios=batch["audios"],
437
+ mode="classify",
438
+ )
439
+ logger.info(" Forward pass OK | logits shape: %s", out["logits"].shape)
440
+ assert out["logits"].shape == (batch["input_ids_a"].size(0), 3), \
441
+ f"Shape inesperado: {out['logits'].shape}"
442
+ except Exception as e:
443
+ errors.append(f"Forward pass inicial falhou: {e}")
444
+ logger.error(traceback.format_exc())
445
+
446
+ # Step 5
447
+ if not errors:
448
+ try:
449
+ train_result = step_05_train(models, tokenizer, dataloader, device="cpu")
450
+ except Exception as e:
451
+ errors.append(f"Treinamento falhou: {e}")
452
+ train_result = None
453
+ else:
454
+ train_result = None
455
+
456
+ # Step 6
457
+ if not errors:
458
+ try:
459
+ step_06_inference(models["model"], tokenizer, device="cpu")
460
+ except Exception as e:
461
+ errors.append(f"Inferência falhou: {e}")
462
+ logger.error(traceback.format_exc())
463
+
464
+ # Step 7
465
+ if not errors:
466
+ try:
467
+ step_07_eval_ppl(models["model"], tokenizer, dataloader, device="cpu")
468
+ except Exception as e:
469
+ warnings.append(f"PPL falhou (não crítico): {e}")
470
+
471
+ # Step 8
472
+ step_08_report_errors(errors, warnings)
473
+
474
+ # Resumo final
475
+ logger.info("=" * 70)
476
+ logger.info("RESUMO FINAL DO TESTE DE 50 AMOSTRAS")
477
+ logger.info("=" * 70)
478
+ logger.info(" Amostras processadas: 50")
479
+ logger.info(" Erros críticos: %d", len(errors))
480
+ logger.info(" Warnings: %d", len(warnings))
481
+ if train_result:
482
+ logger.info(" Loss final: %.4f", train_result["final_loss"])
483
+ logger.info(" PPL final: %.2f", train_result["final_ppl"])
484
+ logger.info(" Tempo: %.1fs", train_result["elapsed_s"])
485
+ logger.info(" Synergy attempts: %d", len(train_result.get("synergy_history", [])))
486
+ logger.info(" Hypothesis activations: %d",
487
+ sum(h.get("hypothesis_activations", 0) for h in train_result.get("history", [])))
488
+
489
+ if errors:
490
+ logger.error(" STATUS: FALHA — %d erro(s)", len(errors))
491
+ return 1
492
+ else:
493
+ logger.info(" STATUS: SUCESSO")
494
+ return 0
495
+
496
+ except Exception as e:
497
+ logger.error("ERRO FATAL: %s", e)
498
+ logger.error(traceback.format_exc())
499
+ return 2
500
+
501
+
502
+ if __name__ == "__main__":
503
+ try:
504
+ rc = main()
505
+ except SystemExit:
506
+ raise
507
+ except Exception as e:
508
+ logger.error("Unhandled exception: %s", e)
509
+ rc = 2
510
+ # Evita o "Fatal Python error: PyGILState_Release" no shutdown causado
511
+ # por threads do tokenizers/datasets que ainda estão ativas.
512
+ import os
513
+ os._exit(rc)