ManasKumar28 commited on
Commit
5ce49e2
·
verified ·
1 Parent(s): 6c83d1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -98
app.py CHANGED
@@ -383,6 +383,7 @@ def build_encoder(config):
383
  # 5. Load the model on CPU
384
  # --------------------------------------------------
385
  model = None
 
386
  encoder = None
387
  LABELS = []
388
  LOAD_ERROR = None
@@ -398,6 +399,12 @@ try:
398
 
399
  config = load_config(ckpt)
400
 
 
 
 
 
 
 
401
  # Build the correctly ordered 27-class encoder.
402
  encoder = build_encoder(config)
403
  LABELS = list(encoder.labels)
@@ -405,29 +412,61 @@ try:
405
  # Build the CRNN student model.
406
  sed_student = CRNN(**config["net"])
407
 
408
- # Load the pretrained BEATs model.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  beats_path = ensure_beats_checkpoint()
410
  beats_ckpt = torch_load(beats_path)
411
 
412
  beats_cfg = BEATsConfig(beats_ckpt["cfg"])
413
- pretrained = BEATs(beats_cfg)
414
-
415
- pretrained.load_state_dict(
416
- beats_ckpt["model"]
417
- )
418
-
419
- pretrained.eval()
420
 
421
- for parameter in pretrained.parameters():
422
  parameter.requires_grad = False
423
 
424
- # Construct the DCASE sound event detection model.
 
425
  model = call_with_supported_kwargs(
426
  SEDTask4,
427
  hparams=config,
428
  encoder=encoder,
429
  sed_student=sed_student,
430
- pretrained_model=pretrained,
431
  opt=None,
432
  train_data=None,
433
  valid_data=None,
@@ -438,33 +477,6 @@ try:
438
  evaluation=False,
439
  )
440
 
441
- # Ensure raw-audio inference can access BEATs even when
442
- # the checkpoint configuration uses precomputed embeddings.
443
- model.pretrained_model = pretrained
444
-
445
- # Load the trained detector weights.
446
- state_dict = ckpt.get("state_dict")
447
-
448
- if not isinstance(state_dict, dict):
449
- raise ValueError(
450
- "The checkpoint does not contain a valid state_dict."
451
- )
452
-
453
- incompat = model.load_state_dict(
454
- state_dict,
455
- strict=False,
456
- )
457
-
458
- print("Checkpoint loaded.")
459
- print(
460
- "Missing state-dict keys:",
461
- len(incompat.missing_keys),
462
- )
463
- print(
464
- "Unexpected state-dict keys:",
465
- len(incompat.unexpected_keys),
466
- )
467
-
468
  model.eval()
469
 
470
  # Quick consistency check.
@@ -493,45 +505,18 @@ finally:
493
  # 6. Inference helpers
494
  # --------------------------------------------------
495
  def compute_embeddings(wav):
496
- """
497
- Extract frame-level BEATs embeddings.
498
 
499
- wav shape: [batch_size, samples]
500
- Expected embedding output: [batch_size, frames, features]
501
  """
502
- helper = getattr(model, "get_embeddings", None)
503
-
504
- if callable(helper):
505
- try:
506
- return helper(wav)
507
- except TypeError:
508
- pass
509
-
510
- pretrained_model = getattr(
511
- model,
512
- "pretrained_model",
513
- None,
514
- )
515
-
516
  if pretrained_model is None:
517
- raise RuntimeError(
518
- "The model has no pretrained BEATs encoder."
519
- )
520
 
521
- padding_mask = torch.zeros_like(
522
- wav,
523
- dtype=torch.bool,
524
- )
525
-
526
- result = pretrained_model.extract_features(
527
- wav,
528
- padding_mask=padding_mask,
529
- )
530
-
531
- if isinstance(result, (tuple, list)):
532
- return result[0]
533
-
534
- return result
535
 
536
 
537
  def forward_strong(wav):
@@ -558,32 +543,14 @@ def forward_strong(wav):
558
  takes_embeddings = True
559
 
560
  if takes_embeddings:
561
- last_error = None
562
-
563
- # Support recipe variants that expect different embedding axes.
564
- for candidate in (
565
- embeddings,
566
- embeddings.transpose(1, 2),
567
- ):
568
- try:
569
- result = detect(
570
- feats,
571
- net,
572
- embeddings=candidate,
573
- )
574
-
575
- break
576
-
577
- except Exception as exc:
578
- last_error = exc
579
-
580
- else:
581
- raise RuntimeError(
582
- "Detector failed with both embedding layouts."
583
- ) from last_error
584
-
585
  else:
586
- result = detect(feats, net)
 
 
 
587
 
588
  # Some recipe versions return (strong_predictions, other_output).
589
  strong = (
@@ -662,6 +629,8 @@ def process_audio(audio_file, threshold):
662
  )
663
 
664
  model.to(device)
 
 
665
 
666
  # Load mono audio at 16 kHz.
667
  wav, _ = librosa.load(
@@ -787,6 +756,11 @@ def process_audio(audio_file, threshold):
787
  model.to("cpu")
788
  except Exception:
789
  pass
 
 
 
 
 
790
 
791
 
792
  # --------------------------------------------------
 
383
  # 5. Load the model on CPU
384
  # --------------------------------------------------
385
  model = None
386
+ pretrained_model = None # Kept separate so its weights are not part of the SED checkpoint.
387
  encoder = None
388
  LABELS = []
389
  LOAD_ERROR = None
 
399
 
400
  config = load_config(ckpt)
401
 
402
+ if config.get("pretrained", {}).get("e2e", False):
403
+ raise ValueError(
404
+ "This app currently targets the official DCASE 2024 baseline "
405
+ "with pretrained.e2e=False and precomputed BEATs embeddings."
406
+ )
407
+
408
  # Build the correctly ordered 27-class encoder.
409
  encoder = build_encoder(config)
410
  LABELS = list(encoder.labels)
 
412
  # Build the CRNN student model.
413
  sed_student = CRNN(**config["net"])
414
 
415
+ # Load only the trained student weights. The official DCASE recipe saves
416
+ # this submodule separately in checkpoint["sed_student"]. Loading the
417
+ # entire Lightning state_dict with strict=False can silently leave the
418
+ # detector partly uninitialized, especially across recipe revisions.
419
+ student_state = ckpt.get("sed_student")
420
+
421
+ if not isinstance(student_state, dict):
422
+ full_state = ckpt.get("state_dict", {})
423
+ if isinstance(full_state, dict):
424
+ prefixes = ("sed_student.", "module.sed_student.")
425
+ for prefix in prefixes:
426
+ extracted = {
427
+ key[len(prefix):]: value
428
+ for key, value in full_state.items()
429
+ if key.startswith(prefix)
430
+ }
431
+ if extracted:
432
+ student_state = extracted
433
+ break
434
+
435
+ if not isinstance(student_state, dict) or not student_state:
436
+ raise ValueError(
437
+ "Could not find trained student weights in checkpoint. "
438
+ "Expected checkpoint['sed_student'] or keys prefixed with 'sed_student.'."
439
+ )
440
+
441
+ # Strict loading is intentional: fail rather than serve random/partial weights.
442
+ sed_student.load_state_dict(student_state, strict=True)
443
+ print(
444
+ f"Loaded student checkpoint strictly ({len(student_state)} tensors)."
445
+ )
446
+
447
+ # Load BEATs separately for online waveform embedding extraction.
448
+ # The official DCASE 2024 baseline uses precomputed BEATs embeddings
449
+ # (pretrained.e2e=False), so BEATs must not be attached to the SEDTask4
450
+ # module or included in its checkpoint state_dict.
451
  beats_path = ensure_beats_checkpoint()
452
  beats_ckpt = torch_load(beats_path)
453
 
454
  beats_cfg = BEATsConfig(beats_ckpt["cfg"])
455
+ pretrained_model = BEATs(beats_cfg)
456
+ pretrained_model.load_state_dict(beats_ckpt["model"], strict=True)
457
+ pretrained_model.eval()
 
 
 
 
458
 
459
+ for parameter in pretrained_model.parameters():
460
  parameter.requires_grad = False
461
 
462
+ # Construct the DCASE detector. It deep-copies the already loaded student
463
+ # into sed_teacher; inference below uses sed_student only.
464
  model = call_with_supported_kwargs(
465
  SEDTask4,
466
  hparams=config,
467
  encoder=encoder,
468
  sed_student=sed_student,
469
+ pretrained_model=None,
470
  opt=None,
471
  train_data=None,
472
  valid_data=None,
 
477
  evaluation=False,
478
  )
479
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  model.eval()
481
 
482
  # Quick consistency check.
 
505
  # 6. Inference helpers
506
  # --------------------------------------------------
507
  def compute_embeddings(wav):
508
+ """Extract frame-level embeddings in the format used by DCASE's BEATsModel.
 
509
 
510
+ Input waveform: [batch, samples].
511
+ Return embeddings: [batch, embedding_channels, frames].
512
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  if pretrained_model is None:
514
+ raise RuntimeError("The BEATs encoder has not been loaded.")
 
 
515
 
516
+ # Match local/beats/BEATs.py -> BEATsModel.forward():
517
+ # BEATs returns [batch, frames, 768]; the detector expects [batch, 768, frames].
518
+ features, _ = pretrained_model.extract_features(wav)
519
+ return features.transpose(1, 2).float()
 
 
 
 
 
 
 
 
 
 
520
 
521
 
522
  def forward_strong(wav):
 
543
  takes_embeddings = True
544
 
545
  if takes_embeddings:
546
+ # compute_embeddings already returns [batch, 768, frames], which is
547
+ # the orientation of the saved DCASE frame_embeddings arrays.
548
+ result = detect(feats, net, embeddings=embeddings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  else:
550
+ raise RuntimeError(
551
+ "This DCASE detect() method does not accept embeddings; "
552
+ "the current checkpoint requires BEATs embeddings."
553
+ )
554
 
555
  # Some recipe versions return (strong_predictions, other_output).
556
  strong = (
 
629
  )
630
 
631
  model.to(device)
632
+ if pretrained_model is not None:
633
+ pretrained_model.to(device)
634
 
635
  # Load mono audio at 16 kHz.
636
  wav, _ = librosa.load(
 
756
  model.to("cpu")
757
  except Exception:
758
  pass
759
+ if pretrained_model is not None:
760
+ try:
761
+ pretrained_model.to("cpu")
762
+ except Exception:
763
+ pass
764
 
765
 
766
  # --------------------------------------------------