PowerMachine commited on
Commit
f34637c
·
verified ·
1 Parent(s): ae39b5f

Delete models/cyclic_reasoning.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. models/cyclic_reasoning.py +0 -411
models/cyclic_reasoning.py DELETED
@@ -1,411 +0,0 @@
1
- """cyclic_reasoning.py — Raciocínio Cíclico (Cyclic Reasoning) para CNN-BiGRU.
2
-
3
- Implementa um módulo de raciocínio iterativo que refina a representação
4
- do modelo através de múltiplos ciclos, cada um alimentado pela saída do
5
- ciclo anterior combinada com uma hipótese nova. O processo para quando
6
- a convergência é atingida (norma da diferença < epsilon) ou quando o
7
- número máximo de ciclos é alcançado.
8
-
9
- ==============================================================================
10
- ANÁLISE MATEMÁTICA E LÓGICA
11
- ==============================================================================
12
-
13
- Seja h_0 ∈ R^d a representação inicial produzida pelo modelo (por exemplo,
14
- a saída fused da CooperativeCNNBiGRU). Em cada ciclo c = 1, 2, ..., C_max,
15
- computamos:
16
-
17
- g_c = HypothesisController(h_{c-1}, penalty_c) ∈ R^d (hipótese)
18
- r_c = RefinementLayer(concat(h_{c-1}, g_c)) ∈ R^d (refinamento)
19
- h_c = LayerNorm(h_{c-1} + alpha_c * r_c) ∈ R^d (novo estado)
20
-
21
- onde:
22
- - alpha_c ∈ [0, 1] é um coeficiente de confiança aprendido:
23
- alpha_c = sigmoid(w_alpha^T h_{c-1} + b_alpha)
24
- - penalty_c é a penalidade do verificador no ciclo c (se > threshold,
25
- uma nova hipótese é ativada — ponte com o HypothesisController)
26
- - O critério de parada é:
27
- ||h_c - h_{c-1}||_2 < epsilon
28
- ou c == C_max.
29
-
30
- GARANTIAS MATEMÁTICAS:
31
- 1. CONTRAÇÃO: como LayerNorm normaliza para norma unitária (≈1) e
32
- alpha_c ≤ 1, então ||h_c|| ≤ ||h_{c-1}|| + ||r_c|| (limitado em R^d).
33
- A sequência {h_c} é de Cauchy se o refinement for Lipschitz com L < 1.
34
- 2. CONVERGÊNCIA: empírica e empiricamente observada em ≤ 4 ciclos para
35
- tarefas NLP comuns.
36
- 3. DIFERENCIABILIDADE: todas as operações são diferenciáveis, permitindo
37
- backpropagation através dos ciclos (BPTT — Backprop Through Time).
38
- Para reduzir o custo computacional, suportamos truncamento (truncated
39
- BPTT) preservando apenas os últimos K ciclos no grafo.
40
-
41
- INTEGRAÇÃO COM OUTROS MÓDULOS:
42
- - HypothesisController (cnn_bigru.training.hypothesis_controller): gera
43
- g_c quando penalty_c > threshold.
44
- - EWC (cnn_bigru.utils.ewc): os parâmetros do refinement são protegidos
45
- pelo EWC entre tarefas.
46
- - AntiHallucinationLayer: aplicada em h_c para validar coerência lógica
47
- (tau ≥ tau_min antes de aceitar o ciclo).
48
-
49
- Autor: CNN-BiGRU Project
50
- """
51
- from __future__ import annotations
52
-
53
- import logging
54
- import math
55
- from dataclasses import dataclass, field
56
- from typing import Callable, Dict, List, Optional, Tuple
57
-
58
- import torch
59
- import torch.nn as nn
60
- import torch.nn.functional as F
61
-
62
- logger = logging.getLogger(__name__)
63
-
64
-
65
- # ============================================================================
66
- # Configuração
67
- # ============================================================================
68
-
69
- @dataclass
70
- class CyclicReasoningConfig:
71
- """Configuração do módulo de raciocínio cíclico."""
72
- embed_dim: int = 128 # dimensão da representação h
73
- max_cycles: int = 4 # número máximo de ciclos C_max
74
- convergence_eps: float = 1e-3 # epsilon para parada antecipada
75
- use_truncated_bptt: bool = True # se True, detach após K ciclos
76
- bptt_truncate: int = 2 # K ciclos preservados no grafo
77
- use_layer_norm: bool = True # LayerNorm após cada ciclo
78
- use_residual: bool = True # conexão residual h_{c-1} + alpha * r_c
79
- hypothesis_input_dim: Optional[int] = None # dim do vetor de penalidade (default: embed_dim)
80
- refinement_hidden_mult: int = 4 # multiplicador da camada oculta
81
- dropout: float = 0.1 # dropout no refinement
82
- penalty_threshold: float = 0.5 # ativa nova hipótese se penalty > threshold
83
- use_anti_hallucination_gate: bool = True # porta lógica fuzzy no h_c
84
- device: str = "cpu"
85
-
86
-
87
- # ============================================================================
88
- # Refinement Layer (refina a representação a cada ciclo)
89
- # ============================================================================
90
-
91
- class RefinementLayer(nn.Module):
92
- """Camada de refinamento que combina estado + hipótese.
93
-
94
- R(conv(h, g)) = Linear(GELU(Linear(concat(h, g))))
95
- """
96
-
97
- def __init__(
98
- self,
99
- embed_dim: int,
100
- hypothesis_dim: Optional[int] = None,
101
- hidden_mult: int = 4,
102
- dropout: float = 0.1,
103
- ):
104
- super().__init__()
105
- h_dim = hypothesis_dim or embed_dim
106
- # Camada de fusão: concat(h, g) -> hidden
107
- self.fuse = nn.Linear(embed_dim + h_dim, embed_dim * hidden_mult)
108
- self.dropout = nn.Dropout(dropout)
109
- # Camada de projeção: hidden -> embed_dim
110
- self.proj = nn.Linear(embed_dim * hidden_mult, embed_dim)
111
- # Inicialização ortogonal para estabilidade (dados.txt linha ~880)
112
- for layer in (self.fuse, self.proj):
113
- for name, p in layer.named_parameters():
114
- if "weight" in name and p.dim() >= 2:
115
- try:
116
- nn.init.orthogonal_(p)
117
- except Exception:
118
- nn.init.xavier_uniform_(p)
119
- elif "bias" in name:
120
- nn.init.zeros_(p)
121
-
122
- def forward(self, h: torch.Tensor, g: Optional[torch.Tensor] = None) -> torch.Tensor:
123
- """
124
- Args:
125
- h: [B, D] estado atual
126
- g: [B, D_h] hipótese (opcional — se None, usa zeros)
127
- Returns:
128
- r: [B, D] refinamento
129
- """
130
- if g is None:
131
- g = torch.zeros_like(h)
132
- elif g.size(-1) != h.size(-1):
133
- # projetar g para dim h
134
- if not hasattr(self, "_g_proj"):
135
- self._g_proj = nn.Linear(g.size(-1), h.size(-1), bias=False).to(g.device)
136
- nn.init.orthogonal_(self._g_proj.weight)
137
- g = self._g_proj(g)
138
- x = torch.cat([h, g], dim=-1)
139
- x = self.dropout(F.gelu(self.fuse(x)))
140
- return self.proj(x)
141
-
142
-
143
- # ============================================================================
144
- # Confidence Gate (alpha_c)
145
- # ============================================================================
146
-
147
- class ConfidenceGate(nn.Module):
148
- """Computa alpha_c = sigmoid(w^T h + b) ∈ [0, 1].
149
-
150
- Determina o quanto da hipótese refinada deve ser aceita no novo estado.
151
- """
152
-
153
- def __init__(self, embed_dim: int):
154
- super().__init__()
155
- self.gate = nn.Linear(embed_dim, 1)
156
- nn.init.zeros_(self.gate.bias)
157
-
158
- def forward(self, h: torch.Tensor) -> torch.Tensor:
159
- # Retorna [B, 1] para broadcast
160
- return torch.sigmoid(self.gate(h))
161
-
162
-
163
- # ============================================================================
164
- # Anti-Hallucination Gate (lógica fuzzy de Łukasiewicz simplificada)
165
- # ============================================================================
166
-
167
- class FuzzyLogicGate(nn.Module):
168
- """Porta lógica fuzzy baseada em Łukasiewicz (conforme dados.txt linhas 510-540).
169
-
170
- Computa um valor de verdade suave tau ∈ [0, 1] que mede a coerência
171
- lógica do estado h_c. Se tau < tau_min, o ciclo é rejeitado (h permanece).
172
- """
173
-
174
- def __init__(self, embed_dim: int, tau_min: float = 0.3):
175
- super().__init__()
176
- # Projeção para um escalar (representando o "valor de verdade")
177
- self.proj = nn.Linear(embed_dim, 1)
178
- self.tau_min = tau_min
179
- nn.init.zeros_(self.proj.bias)
180
-
181
- def forward(self, h: torch.Tensor) -> torch.Tensor:
182
- """Retorna tau ∈ [0, 1] — [B, 1]."""
183
- # sigmoid(w^T h + b) — suaviza para [0, 1]
184
- return torch.sigmoid(self.proj(h))
185
-
186
- def accept(self, tau: torch.Tensor) -> torch.Tensor:
187
- """Máscara booleana [B, 1]: True se tau >= tau_min."""
188
- return (tau >= self.tau_min).float()
189
-
190
-
191
- # ============================================================================
192
- # Cyclic Reasoning Module
193
- # ============================================================================
194
-
195
- class CyclicReasoning(nn.Module):
196
- """Módulo de raciocínio cíclico iterativo.
197
-
198
- Aplica múltiplos ciclos de refinamento sobre a representação inicial,
199
- parando antecipadamente quando a convergência é atingida.
200
-
201
- Args:
202
- config: configuração do módulo
203
- """
204
-
205
- def __init__(self, config: CyclicReasoningConfig):
206
- super().__init__()
207
- self.config = config
208
- self.embed_dim = config.embed_dim
209
-
210
- # Camadas compartilhadas entre ciclos (weight sharing) — reduz parâmetros
211
- # Alternativa: um RefinementLayer por ciclo (mais capacidade, mais parâmetros)
212
- self.refinement = RefinementLayer(
213
- embed_dim=config.embed_dim,
214
- hypothesis_dim=config.hypothesis_input_dim,
215
- hidden_mult=config.refinement_hidden_mult,
216
- dropout=config.dropout,
217
- )
218
- self.confidence_gate = ConfidenceGate(config.embed_dim)
219
- self.fuzzy_gate = (
220
- FuzzyLogicGate(config.embed_dim) if config.use_anti_hallucination_gate else None
221
- )
222
- self.ln = nn.LayerNorm(config.embed_dim) if config.use_layer_norm else None
223
-
224
- def forward(
225
- self,
226
- h0: torch.Tensor,
227
- hypothesis_fn: Optional[Callable[[torch.Tensor, int], Optional[torch.Tensor]]] = None,
228
- penalty_signal: Optional[torch.Tensor] = None,
229
- return_history: bool = False,
230
- ) -> Dict[str, torch.Tensor]:
231
- """Executa raciocínio cíclico.
232
-
233
- Args:
234
- h0: [B, D] representação inicial
235
- hypothesis_fn: função (h_c, c) -> g_c (hipótese opcional para ciclo c).
236
- Se None, g_c = None (sem hipótese).
237
- penalty_signal: [B] ou [B, 1] penalidade do verificador (para log).
238
- return_history: se True, retorna lista de h_c por ciclo.
239
-
240
- Returns:
241
- dict com:
242
- h_final: [B, D] estado final
243
- n_cycles: int — número de ciclos executados
244
- converged: bool — se convergiu antes de C_max
245
- deltas: lista de ||h_c - h_{c-1}|| por ciclo
246
- history: lista de h_c (se return_history=True)
247
- alphas: lista de alpha_c
248
- taus: lista de tau_c (se fuzzy gate ativo)
249
- """
250
- if h0.dim() != 2:
251
- raise ValueError(f"h0 deve ser [B, D]; recebido {h0.shape}")
252
-
253
- B, D = h0.shape
254
- if D != self.embed_dim:
255
- raise ValueError(f"embed_dim mismatch: h0={D}, config={self.embed_dim}")
256
-
257
- h = h0
258
- history: List[torch.Tensor] = [h0]
259
- deltas: List[float] = []
260
- alphas: List[float] = []
261
- taus: List[float] = []
262
- converged = False
263
- n_cycles_exec = 0
264
-
265
- for c in range(self.config.max_cycles):
266
- n_cycles_exec = c + 1
267
-
268
- # Truncated BPTT: detach após K ciclos
269
- if (
270
- self.config.use_truncated_bptt
271
- and c >= self.config.bptt_truncate
272
- ):
273
- h = h.detach()
274
-
275
- # 1. Gerar hipótese g_c (se função fornecida)
276
- g_c = None
277
- if hypothesis_fn is not None:
278
- try:
279
- g_c = hypothesis_fn(h, c)
280
- except Exception as e:
281
- logger.debug("hypothesis_fn falhou no ciclo %d: %s", c, e)
282
- g_c = None
283
-
284
- # 2. Refinamento
285
- r_c = self.refinement(h, g_c)
286
-
287
- # 3. Coeficiente de confiança
288
- alpha_c = self.confidence_gate(h) # [B, 1]
289
-
290
- # 4. Novo estado
291
- if self.config.use_residual:
292
- h_new = h + alpha_c * r_c
293
- else:
294
- h_new = alpha_c * r_c
295
-
296
- # 5. Anti-hallucination gate
297
- if self.fuzzy_gate is not None:
298
- tau_c = self.fuzzy_gate(h_new) # [B, 1]
299
- accept_mask = self.fuzzy_gate.accept(tau_c) # [B, 1] em {0, 1}
300
- h_new = h * (1 - accept_mask) + h_new * accept_mask
301
- taus.append(float(tau_c.mean().detach()))
302
- else:
303
- tau_c = None
304
-
305
- # 6. LayerNorm
306
- if self.ln is not None:
307
- h_new = self.ln(h_new)
308
-
309
- # 7. Convergência (delta = ||h_new - h||)
310
- with torch.no_grad():
311
- delta = (h_new - h).norm(dim=-1).mean().item()
312
- deltas.append(delta)
313
- alphas.append(float(alpha_c.mean().detach()))
314
-
315
- h = h_new
316
- history.append(h)
317
-
318
- # 8. Parada antecipada
319
- if delta < self.config.convergence_eps:
320
- converged = True
321
- logger.debug(
322
- "CyclicReasoning convergiu no ciclo %d (delta=%.6f < eps=%.6f)",
323
- c + 1, delta, self.config.convergence_eps,
324
- )
325
- break
326
-
327
- result = {
328
- "h_final": h,
329
- "n_cycles": n_cycles_exec,
330
- "converged": converged,
331
- "deltas": deltas,
332
- "alphas": alphas,
333
- "taus": taus,
334
- }
335
- if return_history:
336
- result["history"] = history
337
- if penalty_signal is not None:
338
- result["penalty_signal"] = penalty_signal
339
- return result
340
-
341
-
342
- # ============================================================================
343
- # Helper: hypothesis_fn factory a partir do HypothesisController
344
- # ============================================================================
345
-
346
- def make_hypothesis_fn(hypothesis_controller, penalty_threshold: float = 0.5):
347
- """Cria uma função hypothesis_fn (h_c, c) -> g_c a partir do HypothesisController.
348
-
349
- O HypothesisController gera hipóteses quando ativado por penalidades.
350
- Esta função adapta a interface para uso no CyclicReasoning.
351
- """
352
- def hypothesis_fn(h_c: torch.Tensor, c: int) -> Optional[torch.Tensor]:
353
- try:
354
- # Tenta chamar o método generate_hypothesis do controller
355
- if hasattr(hypothesis_controller, "generate_hypothesis"):
356
- # Passa h_c como estado e retorna a hipótese (projeta se necessário)
357
- hyp = hypothesis_controller.generate_hypothesis(h_c)
358
- if hyp is None:
359
- return None
360
- # Se dim diferente, projeta
361
- if hasattr(hyp, "dim") and hyp.dim() == 2 and hyp.size(-1) != h_c.size(-1):
362
- if not hasattr(hypothesis_controller, "_proj_to_h"):
363
- hypothesis_controller._proj_to_h = nn.Linear(
364
- hyp.size(-1), h_c.size(-1), bias=False
365
- ).to(hyp.device)
366
- nn.init.orthogonal_(hypothesis_controller._proj_to_h.weight)
367
- hyp = hypothesis_controller._proj_to_h(hyp)
368
- return hyp
369
- return None
370
- except Exception as e:
371
- logger.debug("hypothesis_fn erro: %s", e)
372
- return None
373
-
374
- return hypothesis_fn
375
-
376
-
377
- # ============================================================================
378
- # Demo / Teste rápido
379
- # ============================================================================
380
-
381
- def _self_test():
382
- """Teste rápido do módulo."""
383
- torch.manual_seed(42)
384
- config = CyclicReasoningConfig(
385
- embed_dim=64,
386
- max_cycles=5,
387
- convergence_eps=1e-3,
388
- use_anti_hallucination_gate=True,
389
- )
390
- cr = CyclicReasoning(config)
391
- h0 = torch.randn(4, 64)
392
- result = cr(h0, return_history=True)
393
- print(f"n_cycles={result['n_cycles']}, converged={result['converged']}")
394
- print(f"deltas={result['deltas']}")
395
- print(f"alphas={result['alphas']}")
396
- print(f"taus={result['taus']}")
397
- print(f"h_final shape={result['h_final'].shape}")
398
-
399
-
400
- if __name__ == "__main__":
401
- _self_test()
402
-
403
-
404
- __all__ = [
405
- "CyclicReasoningConfig",
406
- "RefinementLayer",
407
- "ConfidenceGate",
408
- "FuzzyLogicGate",
409
- "CyclicReasoning",
410
- "make_hypothesis_fn",
411
- ]