PowerMachine commited on
Commit
d86c8af
·
verified ·
1 Parent(s): 7bbc32a

Delete cnn_bigru/inference/inference.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. cnn_bigru/inference/inference.py +0 -257
cnn_bigru/inference/inference.py DELETED
@@ -1,257 +0,0 @@
1
- """inference.py — Inferência com Temperatura, Top-K, Top-P e Penalidades.
2
-
3
- Implementa as técnicas descritas em dados.txt (seção sobre geração avançada):
4
- 1. Temperatura: ajusta entropia das previsões
5
- 2. Top-K: filtra os K tokens mais prováveis
6
- 3. Top-P (Nucleus Sampling): limite dinâmico por probabilidade acumulada
7
- 4. Presence Penalty: pune se já apareceu
8
- 5. Frequency Penalty: pune proporcionalmente à frequência
9
- """
10
- from __future__ import annotations
11
-
12
- import logging
13
- import math
14
- from typing import Dict, List, Optional, Tuple
15
-
16
- import torch
17
- import torch.nn as nn
18
- import torch.nn.functional as F
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
-
23
- @torch.no_grad()
24
- def generate_with_sampling(
25
- model: nn.Module,
26
- tokenizer,
27
- prompt_a: str,
28
- prompt_b: str = "",
29
- images: Optional[torch.Tensor] = None,
30
- audios: Optional[torch.Tensor] = None,
31
- max_new_tokens: int = 32,
32
- temperature: float = 0.7,
33
- top_k: int = 40,
34
- top_p: float = 0.9,
35
- presence_penalty: float = 0.3,
36
- frequency_penalty: float = 0.3,
37
- device: str = "cpu",
38
- ) -> Dict[str, any]:
39
- """Gera texto com amostragem avançada.
40
-
41
- Args:
42
- model: MultimodalCNNBiGRU
43
- tokenizer: BBPETokenizer
44
- prompt_a, prompt_b: textos de entrada
45
- images, audios: tensores opcionais
46
- max_new_tokens: máximo de tokens a gerar
47
- temperature: ajusta entropia (0 = greedy)
48
- top_k: filtra K mais prováveis
49
- top_p: limite de probabilidade acumulada
50
- presence_penalty: pune token se já apareceu
51
- frequency_penalty: pune proporcionalmente à frequência
52
- device: dispositivo de computação
53
-
54
- Returns:
55
- dict com:
56
- text: texto gerado
57
- token_ids: lista de IDs gerados
58
- metrics: dicionário de métricas
59
- """
60
- model.eval()
61
-
62
- # Tokeniza prompts
63
- ids_a = tokenizer.encode(prompt_a, add_special=True)
64
- ids_b = tokenizer.encode(prompt_b, add_special=True) if prompt_b else [tokenizer.pad_id] * len(ids_a)
65
-
66
- # Pad para mesmo comprimento
67
- max_len = max(len(ids_a), len(ids_b), 8)
68
- pad_id = tokenizer.pad_id
69
- ids_a = ids_a + [pad_id] * (max_len - len(ids_a))
70
- ids_b = ids_b + [pad_id] * (max_len - len(ids_b))
71
-
72
- input_a = torch.tensor([ids_a], dtype=torch.long, device=device)
73
- input_b = torch.tensor([ids_b], dtype=torch.long, device=device)
74
-
75
- # Prepara imagens/áudios
76
- if images is not None:
77
- images = images.unsqueeze(0).to(device) if images.dim() == 3 else images.to(device)
78
- if audios is not None:
79
- audios = audios.unsqueeze(0).to(device) if audios.dim() == 3 else audios.to(device)
80
-
81
- # Histórico de contagem para penalidades
82
- token_counts: Dict[int, int] = {}
83
- generated_ids: List[int] = []
84
-
85
- eos_id = tokenizer.eos_id
86
- bos_id = tokenizer.bos_id
87
-
88
- metrics = {
89
- "steps": 0,
90
- "fallback_to_greedy": 0,
91
- "tokens_after_topk": 0,
92
- "tokens_after_topp": 0,
93
- }
94
-
95
- for step in range(max_new_tokens):
96
- metrics["steps"] += 1
97
-
98
- # Forward
99
- try:
100
- out = model(
101
- input_a, input_b,
102
- images=images, audios=audios,
103
- mode="generate",
104
- )
105
- logits = out["logits"] # [B, V] ou [B, T, V]
106
- if logits.dim() == 3:
107
- logits = logits[:, -1, :] # pega último token
108
- logits = logits.clone() # [1, V]
109
- except Exception as e:
110
- logger.warning("Forward falhou no step %d: %s", step, e)
111
- break
112
-
113
- # Penalidades de repetição
114
- if presence_penalty != 0.0 or frequency_penalty != 0.0:
115
- for tok_id, count in token_counts.items():
116
- logits[0, tok_id] -= (presence_penalty + count * frequency_penalty)
117
-
118
- # Temperatura
119
- if temperature > 0.0:
120
- logits = logits / temperature
121
- else:
122
- # Greedy
123
- next_token = torch.argmax(logits, dim=-1, keepdim=True)
124
- tok_id = next_token.item()
125
- if tok_id == eos_id:
126
- break
127
- generated_ids.append(tok_id)
128
- token_counts[tok_id] = token_counts.get(tok_id, 0) + 1
129
- metrics["fallback_to_greedy"] += 1
130
- # Anexa ao input
131
- input_a = torch.cat([input_a, next_token], dim=1)
132
- input_b = torch.cat([input_b, next_token], dim=1)
133
- continue
134
-
135
- # Top-K
136
- if top_k > 0:
137
- k = min(top_k, logits.size(-1))
138
- top_vals, _ = torch.topk(logits, k)
139
- thresh = top_vals[:, -1:]
140
- logits[logits < thresh] = float("-inf")
141
- metrics["tokens_after_topk"] = k
142
-
143
- # Top-P (Nucleus)
144
- if top_p < 1.0:
145
- sorted_logits, sorted_idx = torch.sort(logits, descending=True)
146
- sorted_probs = F.softmax(sorted_logits, dim=-1)
147
- cum_probs = torch.cumsum(sorted_probs, dim=-1)
148
-
149
- remove = cum_probs > top_p
150
- remove[:, 1:] = remove[:, :-1].clone()
151
- remove[:, 0] = False
152
-
153
- indices_to_remove = remove.scatter(1, sorted_idx, remove)
154
- logits[indices_to_remove] = float("-inf")
155
- metrics["tokens_after_topp"] = int((~indices_to_remove[0]).sum().item())
156
-
157
- # Amostragem
158
- probs = F.softmax(logits, dim=-1)
159
- try:
160
- next_token = torch.multinomial(probs, num_samples=1)
161
- except Exception as e:
162
- logger.warning("Multinomial falhou: %s — usando argmax", e)
163
- next_token = torch.argmax(probs, dim=-1, keepdim=True)
164
-
165
- tok_id = next_token.item()
166
- if tok_id == eos_id:
167
- break
168
-
169
- generated_ids.append(tok_id)
170
- token_counts[tok_id] = token_counts.get(tok_id, 0) + 1
171
-
172
- # Anexa ao input (mantém janela)
173
- max_seq = 64 # janela máxima
174
- input_a = torch.cat([input_a, next_token], dim=1)[:, -max_seq:]
175
- input_b = torch.cat([input_b, next_token], dim=1)[:, -max_seq:]
176
-
177
- # Decodifica
178
- text = tokenizer.decode(generated_ids, skip_special=True)
179
-
180
- return {
181
- "text": text,
182
- "token_ids": generated_ids,
183
- "metrics": metrics,
184
- }
185
-
186
-
187
- @torch.no_grad()
188
- def evaluate_perplexity(
189
- model: nn.Module,
190
- dataloader,
191
- tokenizer,
192
- device: str = "cpu",
193
- max_batches: int = 10,
194
- ) -> Dict[str, float]:
195
- """Avalia perplexidade do modelo em um dataloader.
196
-
197
- PPL = exp(loss_media)
198
- """
199
- model.eval()
200
- total_loss = 0.0
201
- total_tokens = 0
202
- pad_id = tokenizer.pad_id
203
-
204
- n_batches = 0
205
- for batch_idx, batch in enumerate(dataloader):
206
- if batch_idx >= max_batches:
207
- break
208
-
209
- input_ids_a = batch["input_ids_a"].to(device)
210
- input_ids_b = batch["input_ids_b"].to(device)
211
- images = batch["images"].to(device)
212
- audios = batch["audios"].to(device)
213
- attn_mask_a = batch["attn_mask_a"].to(device)
214
- attn_mask_b = batch["attn_mask_b"].to(device)
215
-
216
- try:
217
- out = model(
218
- input_ids_a, input_ids_b,
219
- images=images, audios=audios,
220
- attn_mask_a=attn_mask_a, attn_mask_b=attn_mask_b,
221
- mode="generate",
222
- )
223
- logits = out["logits"] # [B, V]
224
- # Para PPL, usamos input_ids_b como target (próximo token)
225
- # Expandimos logits para [B, T, V]
226
- B = logits.size(0)
227
- T = input_ids_b.size(1)
228
- V = logits.size(-1)
229
- expanded = logits.unsqueeze(1).expand(-1, T, -1)
230
-
231
- loss = F.cross_entropy(
232
- expanded.reshape(B * T, V),
233
- input_ids_b.reshape(B * T),
234
- ignore_index=pad_id,
235
- reduction="sum",
236
- )
237
- n_tokens = (input_ids_b != pad_id).sum().item()
238
- total_loss += loss.item()
239
- total_tokens += n_tokens
240
- n_batches += 1
241
- except Exception as e:
242
- logger.warning("PPL batch %d falhou: %s", batch_idx, e)
243
- continue
244
-
245
- if total_tokens == 0:
246
- return {"loss": float("inf"), "ppl": float("inf"), "n_batches": 0}
247
-
248
- avg_loss = total_loss / total_tokens
249
- try:
250
- ppl = math.exp(min(avg_loss, 20))
251
- except OverflowError:
252
- ppl = float("inf")
253
-
254
- return {"loss": avg_loss, "ppl": ppl, "n_batches": n_batches}
255
-
256
-
257
- __all__ = ["generate_with_sampling", "evaluate_perplexity"]