Return (WER %, mean validation loss).
(
model: nn.Module,
loader: DataLoader,
device: torch.device,
loss_fn: nn.Module,
)
| 195 | |
| 196 | @torch.no_grad() |
| 197 | def evaluate( |
| 198 | model: nn.Module, |
| 199 | loader: DataLoader, |
| 200 | device: torch.device, |
| 201 | loss_fn: nn.Module, |
| 202 | ) -> tuple[float, float]: |
| 203 | """Return (WER %, mean validation loss).""" |
| 204 | model.eval() |
| 205 | total_edits = total_words = 0 |
| 206 | val_loss_sum = 0.0 |
| 207 | val_steps = 0 |
| 208 | first_batch_done = False |
| 209 | for feats, feat_lens, tgts, tgt_lens, refs in tqdm(loader, leave=False): |
| 210 | feats = feats.to(device, non_blocking=True) |
| 211 | feat_lens = feat_lens.to(device, non_blocking=True) |
| 212 | tgts = tgts.to(device, non_blocking=True) |
| 213 | tgt_lens = tgt_lens.to(device, non_blocking=True) |
| 214 | |
| 215 | logits, logit_lens = model(feats, feat_lens) |
| 216 | |
| 217 | vloss = loss_fn( |
| 218 | logits.transpose(0, 1), |
| 219 | tgts, logit_lens, tgt_lens |
| 220 | ) |
| 221 | val_loss_sum += vloss.item() |
| 222 | val_steps += 1 |
| 223 | |
| 224 | hyps = greedy_decode(logits.cpu(), logit_lens.cpu()) |
| 225 | |
| 226 | if not first_batch_done: |
| 227 | print("\n── Decoding debug (first batch) ──") |
| 228 | for ref, hyp in list(zip(refs, hyps)): |
| 229 | print(f"REF: {ref.lower()}", f"\nHYP: {hyp}") |
| 230 | first_batch_done = True |
| 231 | |
| 232 | for ref, hyp in zip(refs, hyps): |
| 233 | total_edits += F.edit_distance(ref.split(), hyp.split()) |
| 234 | total_words += len(ref.split()) |
| 235 | |
| 236 | wer = 100 * total_edits / total_words if total_words else 0.0 |
| 237 | val_loss = val_loss_sum / max(val_steps, 1) |
| 238 | return wer, val_loss |
| 239 | |
| 240 | # ----------------------------------------------------------------------------- |
| 241 | # Argument parsing |
no test coverage detected