PowerMachine commited on
Commit
078b56b
·
verified ·
1 Parent(s): 6a37d81

Delete losses/losses.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. losses/losses.py +0 -271
losses/losses.py DELETED
@@ -1,271 +0,0 @@
1
- """losses.py — Sistema de múltiplas perdas para o CNN-BiGRU cooperativo.
2
-
3
- Implementa as perdas descritas na seção 8 de dados.txt:
4
-
5
- L_G = CrossEntropy(logits_prova, prova_alvo)
6
- L_penal = λ * Σ (1 - v_t) (penalidade linear)
7
- L_exp_penal = μ * Σ exp(γ * (1 - v_t)) (penalidade exponencial)
8
- L_V = BCE(v_t, rotulo_real) (perda do verificador)
9
- L_AH = Σ (1 - τ_t) (perda anti-alucinação)
10
- L_reg = L2 + estimativa de curvatura (regularização)
11
- L_total = α * L_G_total + β * L_V + γ_loss * L_AH + δ * L_reg
12
-
13
- onde:
14
- L_G_total = L_G + λ_penal * L_penal + μ_exp * L_exp_penal
15
- """
16
- from __future__ import annotations
17
-
18
- import logging
19
- import math
20
- from dataclasses import dataclass, field
21
- from typing import Dict, List, Optional
22
-
23
- import torch
24
- import torch.nn as nn
25
- import torch.nn.functional as F
26
-
27
- logger = logging.getLogger(__name__)
28
-
29
-
30
- @dataclass
31
- class LossConfig:
32
- """Configuração das perdas e pesos."""
33
- # Pesos das perdas (ALPHA, BETA, GAMMA, DELTA do pseudocódigo)
34
- alpha: float = 1.0 # peso de L_G_total
35
- beta: float = 0.5 # peso de L_V
36
- gamma_loss: float = 0.3 # peso de L_AH
37
- delta: float = 0.01 # peso de L_reg
38
-
39
- # Penalidades
40
- lambda_penal: float = 0.1 # LAMBDA_PENAL
41
- mu_exp_penal: float = 0.05 # MU_EXP_PENAL
42
- gamma_exp: float = 1.0 # GAMMA_EXP
43
- threshold_err: float = 0.5 # THRESHOLD_ERR para penalidade exponencial
44
-
45
- # Regularização
46
- l2_reg: float = 1e-5
47
-
48
- # Curvatura
49
- use_curvature: bool = True
50
- curvature_eps: float = 1e-3
51
-
52
-
53
- class MultiLoss(nn.Module):
54
- """Computa todas as perdas do sistema cooperativo.
55
-
56
- Uso:
57
- loss_fn = MultiLoss(cfg)
58
- result = loss_fn(logits, targets, v_list, tau_list, generator, verifier)
59
- loss = result['total']
60
- loss.backward()
61
- """
62
-
63
- def __init__(self, config: LossConfig, pad_idx: int = 1):
64
- super().__init__()
65
- self.cfg = config
66
- self.pad_idx = pad_idx
67
- self.ce = nn.CrossEntropyLoss(ignore_index=pad_idx, reduction='mean')
68
- self.bce = nn.BCELoss(reduction='mean')
69
-
70
- def generation_loss(
71
- self,
72
- logits: torch.Tensor, # [B, T, V]
73
- targets: torch.Tensor, # [B, T]
74
- ) -> torch.Tensor:
75
- """L_G: CrossEntropy ignorando padding."""
76
- B, T, V = logits.shape
77
- return self.ce(logits.reshape(B * T, V), targets.reshape(B * T))
78
-
79
- def penalty_loss(
80
- self,
81
- v_list: List[torch.Tensor], # lista de [B, 1] probabilidades do verificador
82
- ) -> Dict[str, torch.Tensor]:
83
- """Calcula L_penal (linear) e L_exp_penal (exponencial).
84
-
85
- Fórmulas (dados.txt seção 8.2):
86
- L_penal = Σ_t (1 - v_t) (linear, todos os passos)
87
- L_exp_penal = Σ_{t: v_t < threshold} exp(γ * (1 - v_t)) (exponencial, apenas graves)
88
- """
89
- if not v_list:
90
- # Retorna zero no device do próprio MultiLoss (que está em algum dispositivo)
91
- device = next(self.parameters(), torch.tensor(0.0)).device if any(
92
- p.requires_grad for p in self.parameters()
93
- ) else torch.device("cpu")
94
- zero = torch.zeros((), device=device)
95
- return {"linear": zero, "exp": zero}
96
-
97
- # Stack: [T, B, 1] -> [T, B]
98
- v_stack = torch.stack([v.squeeze(-1) if v.dim() == 2 else v for v in v_list], dim=0)
99
- # Penalidade linear: Σ (1 - v) sobre TODOS os passos
100
- l_penal = (1.0 - v_stack).sum() / max(v_stack.numel(), 1)
101
-
102
- # Penalidade exponencial: Σ exp(γ * (1 - v)) onde v < threshold
103
- mask = v_stack < self.cfg.threshold_err
104
- if mask.any():
105
- # exp(γ * (1 - v)) para os graves
106
- exp_vals = torch.exp(self.cfg.gamma_exp * (1.0 - v_stack[mask]))
107
- l_exp = exp_vals.sum() / max(v_stack.numel(), 1)
108
- else:
109
- l_exp = torch.zeros((), device=v_stack.device)
110
-
111
- return {"linear": l_penal, "exp": l_exp}
112
-
113
- def verifier_loss(
114
- self,
115
- v_list: List[torch.Tensor],
116
- labels: List[torch.Tensor], # lista de [B, 1] com 0/1
117
- ) -> torch.Tensor:
118
- """L_V: BCE entre v_t e rotulo_real."""
119
- if not v_list:
120
- # Device-safe zero
121
- device = next(self.parameters(), torch.tensor(0.0)).device if any(
122
- p.requires_grad for p in self.parameters()
123
- ) else torch.device("cpu")
124
- return torch.zeros((), device=device)
125
- # Inicializar no device do primeiro v
126
- first_v = v_list[0]
127
- device = first_v.device
128
- total = torch.zeros((), device=device)
129
- for v, label in zip(v_list, labels):
130
- v_flat = (v.squeeze(-1) if v.dim() == 2 else v).clamp(1e-7, 1 - 1e-7)
131
- label_flat = label.squeeze(-1) if label.dim() == 2 else label
132
- total = total + self.bce(v_flat, label_flat.float().to(device))
133
- return total / max(len(v_list), 1)
134
-
135
- def anti_hallucination_loss(
136
- self,
137
- tau_list: List[torch.Tensor], # lista de [B, 1] valores de verdade suave
138
- ) -> torch.Tensor:
139
- """L_AH = Σ (1 - τ_t)."""
140
- if not tau_list:
141
- device = next(self.parameters(), torch.tensor(0.0)).device if any(
142
- p.requires_grad for p in self.parameters()
143
- ) else torch.device("cpu")
144
- return torch.zeros((), device=device)
145
- first_tau = tau_list[0]
146
- device = first_tau.device
147
- total = torch.zeros((), device=device)
148
- for tau in tau_list:
149
- tau_flat = tau.squeeze(-1) if tau.dim() == 2 else tau
150
- total = total + (1.0 - tau_flat).mean()
151
- return total / max(len(tau_list), 1)
152
-
153
- def regularization_loss(
154
- self,
155
- models: List[nn.Module],
156
- ) -> torch.Tensor:
157
- """L_reg = L2 + estimativa de curvatura (aproximada via norma de pesos)."""
158
- # Determinar device do primeiro parâmetro treinável
159
- device = torch.device("cpu")
160
- for model in models:
161
- for p in model.parameters():
162
- if p.requires_grad:
163
- device = p.device
164
- break
165
- else:
166
- continue
167
- break
168
-
169
- l2 = torch.zeros((), device=device)
170
- for model in models:
171
- for p in model.parameters():
172
- if p.requires_grad:
173
- l2 = l2 + p.pow(2).sum()
174
- l2 = self.cfg.l2_reg * l2
175
-
176
- # Estimativa de curvatura aproximada: variância das normas dos gradientes
177
- # (calculada externamente e passada via attr)
178
- curv = getattr(self, '_curvature_estimate', None)
179
- if curv is None:
180
- curv = torch.zeros((), device=device)
181
- elif isinstance(curv, (int, float)):
182
- curv = torch.tensor(float(curv), device=device)
183
- elif isinstance(curv, torch.Tensor):
184
- curv = curv.to(device)
185
- return l2 + curv
186
-
187
- def set_curvature_estimate(self, value: torch.Tensor) -> None:
188
- """Define a estimativa de curvatura (calculada externamente)."""
189
- self._curvature_estimate = value
190
-
191
- def forward(
192
- self,
193
- logits: torch.Tensor,
194
- targets: torch.Tensor,
195
- v_list: List[torch.Tensor],
196
- tau_list: List[torch.Tensor],
197
- verifier_labels: Optional[List[torch.Tensor]] = None,
198
- models_for_reg: Optional[List[nn.Module]] = None,
199
- ewc_penalty: Optional[torch.Tensor] = None,
200
- ) -> Dict[str, torch.Tensor]:
201
- """Computa todas as perdas e combina.
202
-
203
- Args:
204
- logits: [B, T, V] logits do gerador
205
- targets: [B, T] tokens alvo
206
- v_list: lista de [B, 1] probabilidades do verificador por passo
207
- tau_list: lista de [B, 1] valores anti-alucinação por passo
208
- verifier_labels: lista de [B, 1] rótulos reais (0/1) por passo
209
- models_for_reg: lista de modelos para regularização L2
210
- ewc_penalty: escalar (tensor 0-dim) com a penalidade EWC pré-computada
211
-
212
- Returns:
213
- dict com todas as perdas individuais e a perda total
214
- """
215
- # L_G
216
- l_g = self.generation_loss(logits, targets)
217
-
218
- # Penalidades
219
- pens = self.penalty_loss(v_list)
220
- l_g_total = l_g + self.cfg.lambda_penal * pens["linear"] + self.cfg.mu_exp_penal * pens["exp"]
221
-
222
- # L_V
223
- if verifier_labels is not None:
224
- l_v = self.verifier_loss(v_list, verifier_labels)
225
- else:
226
- # Sem rótulos reais: assume que v deveria ser 1 (passo correto)
227
- labels_ones = [torch.ones_like(v) for v in v_list]
228
- l_v = self.verifier_loss(v_list, labels_ones)
229
-
230
- # L_AH
231
- l_ah = self.anti_hallucination_loss(tau_list)
232
-
233
- # L_reg (L2 + curvatura)
234
- if models_for_reg:
235
- l_reg = self.regularization_loss(models_for_reg)
236
- else:
237
- # Device-safe zero
238
- device = logits.device if isinstance(logits, torch.Tensor) else torch.device("cpu")
239
- l_reg = torch.zeros((), device=device)
240
-
241
- # L_EWC (Elastic Weight Consolidation) — continua aprendizado sem esquecer
242
- if ewc_penalty is not None:
243
- l_ewc = ewc_penalty
244
- else:
245
- device = logits.device if isinstance(logits, torch.Tensor) else torch.device("cpu")
246
- l_ewc = torch.zeros((), device=device)
247
-
248
- # Combinação: L_total = α*L_G_total + β*L_V + γ*L_AH + δ*L_reg + L_EWC
249
- # EWC é somado separadamente (já vem pré-ponderado por lambda_ewc/2)
250
- total = (
251
- self.cfg.alpha * l_g_total
252
- + self.cfg.beta * l_v
253
- + self.cfg.gamma_loss * l_ah
254
- + self.cfg.delta * l_reg
255
- + l_ewc
256
- )
257
-
258
- return {
259
- "total": total,
260
- "l_g": l_g,
261
- "l_g_total": l_g_total,
262
- "l_penal_linear": pens["linear"],
263
- "l_penal_exp": pens["exp"],
264
- "l_v": l_v,
265
- "l_ah": l_ah,
266
- "l_reg": l_reg,
267
- "l_ewc": l_ewc,
268
- }
269
-
270
-
271
- __all__ = ["LossConfig", "MultiLoss"]