PowerMachine commited on
Commit
8793991
·
verified ·
1 Parent(s): 13cc5a0

V6.7: upload src/bigru_t/model/kohonen_learning_system.py (BBPE serial mode + OomGuard V7)

Browse files
src/bigru_t/model/kohonen_learning_system.py CHANGED
@@ -443,6 +443,15 @@ class KohonenSOM4D:
443
  self.fisher_accum = torch.zeros(self.I, self.J, self.K, self.L)
444
  self.fisher_count = torch.zeros(self.I, self.J, self.K, self.L)
445
 
 
 
 
 
 
 
 
 
 
446
  # V6.5-V2-metrics-FIX-4 — Conscience mechanism (DeSieno 1988)
447
  # Inicializa p_i = 1/N (uniforme) — sem viés inicial.
448
  # b_i = γ · (1/N - p_i) começa em 0 (sem bias).
@@ -1392,10 +1401,19 @@ class KohonenSOM4D:
1392
  NaN não deve contaminar permanentemente os pesos).
1393
  3. Clamp dos pesos após update (evita explosão numérica).
1394
 
 
 
 
 
 
 
 
 
1395
  Args:
1396
  x: tensor [4] — amostra 4D.
1397
  bmu_idx: (i, j, k, l) — índice do BMU.
1398
- accumulate_fisher: se True, acumula (x_w - W_w)² nos Fisher accumulators.
 
1399
  """
1400
  # V6.5-V2-metrics-FIX-3 — sanitiza x: substitui NaN/Inf por 0
1401
  # (uma amostra degenerada não deve contaminar todo o SOM).
@@ -1427,13 +1445,16 @@ class KohonenSOM4D:
1427
  if torch.isnan(self.weights).any() or torch.isinf(self.weights).any():
1428
  self.weights = torch.nan_to_num(self.weights, nan=0.0, posinf=100.0, neginf=-100.0)
1429
 
1430
- if accumulate_fisher:
 
 
 
1431
  # Acumula Fisher apenas em neurônios próximos ao BMU (Λ > 0.1)
1432
  mask = h > 0.1
1433
  if mask.any():
1434
  diff_sq = (x[3] - self.weights[mask][..., 3]) ** 2
1435
- self.fisher_accum[mask] += diff_sq
1436
- self.fisher_count[mask] += 1
1437
 
1438
  self.t += 1
1439
 
@@ -1458,16 +1479,41 @@ class KohonenSOM4D:
1458
  pass
1459
 
1460
  def finalize_fisher(self):
1461
- """Fisher = mean((x_w - W_w)²) sobre samples acumuladas."""
 
 
 
 
 
 
1462
  cnt = self.fisher_count.clamp(min=1e-8)
1463
- self.fisher_w = self.fisher_accum / cnt
 
 
 
 
 
 
 
 
 
1464
 
1465
  def set_ewc_reference(self):
1466
- """Consolida W_w como referência EWC e finaliza Fisher."""
 
 
 
 
 
1467
  self.old_weights_w = self.weights[..., 3].clone()
1468
  self.finalize_fisher()
 
1469
  self.fisher_accum.zero_()
1470
  self.fisher_count.zero_()
 
 
 
 
1471
 
1472
  # ------------------------------------------------------------------
1473
  # Métricas para monitoramento (V6.4)
 
443
  self.fisher_accum = torch.zeros(self.I, self.J, self.K, self.L)
444
  self.fisher_count = torch.zeros(self.I, self.J, self.K, self.L)
445
 
446
+ # V6.6 — Fisher accumulation CONTÍNUA (online EWC pattern)
447
+ # Quando True, Fisher é acumulado em TODOS os updates (não só
448
+ # antes da primeira consolidação). Após set_ewc_reference(),
449
+ # Fisher é resetado e começa a acumular novamente para a próxima
450
+ # tarefa. A consolidada é preservada via EMA em finalize_fisher().
451
+ self.fisher_continuous: bool = True
452
+ # Histórico de Fisher consolidations (uma entrada por set_ewc_reference)
453
+ self.fisher_consolidation_count: int = 0
454
+
455
  # V6.5-V2-metrics-FIX-4 — Conscience mechanism (DeSieno 1988)
456
  # Inicializa p_i = 1/N (uniforme) — sem viés inicial.
457
  # b_i = γ · (1/N - p_i) começa em 0 (sem bias).
 
1401
  NaN não deve contaminar permanentemente os pesos).
1402
  3. Clamp dos pesos após update (evita explosão numérica).
1403
 
1404
+ V6.6 — Fisher accumulation CONTÍNUA (online EWC pattern):
1405
+ Quando self.fisher_continuous=True (default), acumula Fisher em
1406
+ TODOS os updates, não apenas quando accumulate_fisher=True.
1407
+ Após set_ewc_reference(), Fisher é resetado e começa a acumular
1408
+ novamente para a próxima tarefa. Isto suporta online EWC
1409
+ (Schwarz et al. 2018) onde múltiplas tarefas são consolidadas
1410
+ sequencialmente sem catastrophic forgetting.
1411
+
1412
  Args:
1413
  x: tensor [4] — amostra 4D.
1414
  bmu_idx: (i, j, k, l) — índice do BMU.
1415
+ accumulate_fisher: se True (ou fisher_continuous=True), acumula
1416
+ (x_w - W_w)² nos Fisher accumulators.
1417
  """
1418
  # V6.5-V2-metrics-FIX-3 — sanitiza x: substitui NaN/Inf por 0
1419
  # (uma amostra degenerada não deve contaminar todo o SOM).
 
1445
  if torch.isnan(self.weights).any() or torch.isinf(self.weights).any():
1446
  self.weights = torch.nan_to_num(self.weights, nan=0.0, posinf=100.0, neginf=-100.0)
1447
 
1448
+ # V6.6 — Fisher accumulation contínua (online EWC)
1449
+ # Acumula SEMPRE que: accumulate_fisher=True OU fisher_continuous=True
1450
+ should_accumulate = accumulate_fisher or getattr(self, 'fisher_continuous', False)
1451
+ if should_accumulate:
1452
  # Acumula Fisher apenas em neurônios próximos ao BMU (Λ > 0.1)
1453
  mask = h > 0.1
1454
  if mask.any():
1455
  diff_sq = (x[3] - self.weights[mask][..., 3]) ** 2
1456
+ self.fisher_accum[mask] = self.fisher_accum[mask] + diff_sq
1457
+ self.fisher_count[mask] = self.fisher_count[mask] + 1
1458
 
1459
  self.t += 1
1460
 
 
1479
  pass
1480
 
1481
  def finalize_fisher(self):
1482
+ """Fisher = mean((x_w - W_w)²) sobre samples acumuladas.
1483
+
1484
+ V6.6 — se fisher_continuous=True E já existe fisher_w (consolidação
1485
+ anterior), faz EMA (exponential moving average) com a Fisher anterior
1486
+ em vez de substituir — isto preserva informação de tarefas passadas
1487
+ (online EWC pattern, cf. Schwarz et al. 2018).
1488
+ """
1489
  cnt = self.fisher_count.clamp(min=1e-8)
1490
+ new_fisher = self.fisher_accum / cnt
1491
+ if (getattr(self, 'fisher_continuous', False)
1492
+ and self.fisher_w is not None
1493
+ and getattr(self, 'fisher_consolidation_count', 0) > 0):
1494
+ # EMA: F_t = α·F_t_new + (1-α)·F_{t-1}
1495
+ # α=0.5 dá peso igual a tarefa atual e à memória das anteriores
1496
+ ema_alpha = 0.5
1497
+ self.fisher_w = ema_alpha * new_fisher + (1 - ema_alpha) * self.fisher_w
1498
+ else:
1499
+ self.fisher_w = new_fisher
1500
 
1501
  def set_ewc_reference(self):
1502
+ """Consolida W_w como referência EWC e finaliza Fisher.
1503
+
1504
+ V6.6 — Após consolidação, Fisher é RESETADO para acumular informação
1505
+ da PRÓXIMA tarefa (online EWC pattern). A Fisher consolidada é
1506
+ preservada em self.fisher_w via EMA em finalize_fisher().
1507
+ """
1508
  self.old_weights_w = self.weights[..., 3].clone()
1509
  self.finalize_fisher()
1510
+ # Reset dos accumuladores para a próxima tarefa
1511
  self.fisher_accum.zero_()
1512
  self.fisher_count.zero_()
1513
+ # V6.6 — Track consolidation count for EMA logic
1514
+ if not hasattr(self, 'fisher_consolidation_count'):
1515
+ self.fisher_consolidation_count = 0
1516
+ self.fisher_consolidation_count += 1
1517
 
1518
  # ------------------------------------------------------------------
1519
  # Métricas para monitoramento (V6.4)