|
1 | 1 | import math |
2 | 2 |
|
3 | 3 | import numpy as np |
4 | | - |
5 | | -try: |
6 | | - import tensorflow as tf |
7 | | -except ImportError: |
8 | | - tf = None |
9 | 4 | from keras import KerasTensor |
10 | 5 | from keras import ops |
11 | 6 | from keras import random |
@@ -522,153 +517,134 @@ def call( |
522 | 517 | return_attention_mask=True, |
523 | 518 | ): |
524 | 519 | if isinstance(raw_speech, KerasTensor): |
525 | | - return self.compute_output_spec(raw_speech) |
526 | | - if isinstance(raw_speech, (list, tuple)): |
527 | | - speech_list = [ |
528 | | - np.asarray(speech).reshape(-1) for speech in raw_speech |
529 | | - ] |
530 | | - input_features_list, attention_mask_list = self.pad( |
531 | | - speech_list, |
532 | | - padding=padding, |
533 | | - max_length=max_length, |
534 | | - truncation=truncation, |
535 | | - pad_to_multiple_of=pad_to_multiple_of, |
536 | | - return_attention_mask=return_attention_mask, |
| 520 | + return self.compute_output_spec( |
| 521 | + raw_speech, return_attention_mask=return_attention_mask |
537 | 522 | ) |
538 | | - if not return_attention_mask: |
539 | | - attention_mask_list = [None] * len(input_features_list) |
540 | | - prepared_features = [] |
541 | | - prepared_masks = [] |
542 | | - for speech, mask in zip(input_features_list, attention_mask_list): |
543 | | - speech = ops.convert_to_tensor( |
544 | | - np.asarray(speech).reshape(-1), dtype=self.compute_dtype |
545 | | - ) |
546 | 523 |
|
547 | | - mask_tensor = ( |
548 | | - ops.convert_to_tensor( |
549 | | - np.asarray(mask).reshape(-1), dtype="int32" |
550 | | - ) |
551 | | - if mask is not None |
552 | | - else None |
| 524 | + if ops.is_tensor(raw_speech): |
| 525 | + waveform = ops.cast(raw_speech, dtype=self.compute_dtype) |
| 526 | + waveform_rank = len(ops.shape(waveform)) |
| 527 | + if waveform_rank not in (1, 2): |
| 528 | + raise ValueError( |
| 529 | + f"`raw_speech` must have rank 1 or 2. " |
| 530 | + f"Received shape: {ops.shape(raw_speech)}." |
553 | 531 | ) |
554 | | - |
555 | | - # Single waveform -> 1-D input. |
556 | | - features, feature_mask = self._extract_spectrogram( |
557 | | - speech, mask_tensor |
| 532 | + if ( |
| 533 | + max_length is not None |
| 534 | + and pad_to_multiple_of is not None |
| 535 | + and max_length % pad_to_multiple_of != 0 |
| 536 | + ): |
| 537 | + max_length = ( |
| 538 | + (max_length // pad_to_multiple_of) + 1 |
| 539 | + ) * pad_to_multiple_of |
| 540 | + |
| 541 | + if truncation and max_length is not None: |
| 542 | + waveform = waveform[..., :max_length] |
| 543 | + |
| 544 | + if padding == "max_length" and max_length is not None: |
| 545 | + current_len = ops.shape(waveform)[-1] |
| 546 | + pad_len = ops.maximum(0, max_length - current_len) |
| 547 | + paddings = ( |
| 548 | + [[0, pad_len]] |
| 549 | + if waveform_rank == 1 |
| 550 | + else [[0, 0], [0, pad_len]] |
558 | 551 | ) |
559 | | - features = ops.reshape(features, (-1, self.feature_size)) |
560 | | - if return_attention_mask: |
561 | | - if feature_mask is None: |
562 | | - feature_mask = ops.ones( |
563 | | - (ops.shape(features)[0],), dtype="int32" |
564 | | - ) |
565 | | - else: |
566 | | - feature_mask = ops.reshape(feature_mask, (-1,)) |
567 | | - feature_mask = ops.cast(feature_mask, "int32") |
568 | | - |
569 | | - prepared_masks.append(feature_mask) |
570 | | - prepared_features.append(features) |
571 | | - |
572 | | - input_features = ops.stack(prepared_features, axis=0) |
| 552 | + waveform = ops.pad( |
| 553 | + waveform, paddings, constant_values=self.padding_value |
| 554 | + ) |
| 555 | + elif padding == "longest" and pad_to_multiple_of is not None: |
| 556 | + current_len = ops.shape(waveform)[-1] |
| 557 | + rem = current_len % pad_to_multiple_of |
| 558 | + pad_len = (pad_to_multiple_of - rem) % pad_to_multiple_of |
| 559 | + paddings = ( |
| 560 | + [[0, pad_len]] |
| 561 | + if waveform_rank == 1 |
| 562 | + else [[0, 0], [0, pad_len]] |
| 563 | + ) |
| 564 | + waveform = ops.pad( |
| 565 | + waveform, paddings, constant_values=self.padding_value |
| 566 | + ) |
| 567 | + |
573 | 568 | if return_attention_mask: |
574 | | - input_features_mask = ops.stack(prepared_masks, axis=0) |
| 569 | + current_len = ops.shape(waveform)[-1] |
| 570 | + if waveform_rank == 1: |
| 571 | + mask = ops.ones((current_len,), dtype="int32") |
| 572 | + else: |
| 573 | + batch_size = ops.shape(waveform)[0] |
| 574 | + mask = ops.ones((batch_size, current_len), dtype="int32") |
575 | 575 | else: |
576 | | - input_features_mask = None |
577 | | - return input_features, input_features_mask |
| 576 | + mask = None |
| 577 | + |
| 578 | + features, feature_mask = self._extract_spectrogram(waveform, mask) |
| 579 | + return features, feature_mask |
578 | 580 |
|
| 581 | + # Handle NumPy inputs and determine whether input is batched |
579 | 582 | if isinstance(raw_speech, (list, tuple)): |
580 | | - raw_speech_tensor = ops.stack( |
581 | | - [ |
582 | | - speech |
583 | | - if ops.is_tensor(speech) |
584 | | - else ops.convert_to_tensor(speech) |
585 | | - for speech in raw_speech |
586 | | - ], |
587 | | - axis=0, |
588 | | - ) |
589 | | - elif ops.is_tensor(raw_speech): |
590 | | - raw_speech_tensor = raw_speech |
| 583 | + is_batched = True |
| 584 | + speech_list = [ |
| 585 | + ops.convert_to_numpy(s).reshape(-1) for s in raw_speech |
| 586 | + ] |
591 | 587 | else: |
592 | | - raw_speech_tensor = ops.convert_to_tensor(raw_speech) |
| 588 | + speech_np = ops.convert_to_numpy(raw_speech) |
| 589 | + if speech_np.ndim == 1: |
| 590 | + is_batched = False |
| 591 | + speech_list = [speech_np.reshape(-1)] |
| 592 | + elif speech_np.ndim == 2: |
| 593 | + is_batched = True |
| 594 | + speech_list = [s.reshape(-1) for s in speech_np] |
| 595 | + else: |
| 596 | + raise ValueError( |
| 597 | + f"`raw_speech` must have rank 1 or 2. " |
| 598 | + f"Received shape: {speech_np.shape}." |
| 599 | + ) |
593 | 600 |
|
594 | | - rank = ops.ndim(raw_speech_tensor) |
595 | | - if rank == 1: |
596 | | - speech_np = np.asarray(raw_speech_tensor).reshape(-1) |
| 601 | + # Pad or truncate using self.pad() |
| 602 | + input_features_list, attention_mask_list = self.pad( |
| 603 | + speech_list, |
| 604 | + padding=padding, |
| 605 | + max_length=max_length, |
| 606 | + truncation=truncation, |
| 607 | + pad_to_multiple_of=pad_to_multiple_of, |
| 608 | + return_attention_mask=return_attention_mask, |
| 609 | + ) |
597 | 610 |
|
598 | | - input_features_list, attention_mask_list = self.pad( |
599 | | - [speech_np], |
600 | | - padding=padding, |
601 | | - max_length=max_length, |
602 | | - truncation=truncation, |
603 | | - pad_to_multiple_of=pad_to_multiple_of, |
604 | | - return_attention_mask=return_attention_mask, |
| 611 | + if not input_features_list: |
| 612 | + features = ops.zeros( |
| 613 | + (0, 0, self.feature_size) |
| 614 | + if is_batched |
| 615 | + else (0, self.feature_size), |
| 616 | + dtype=self.compute_dtype, |
605 | 617 | ) |
606 | | - if not input_features_list: |
607 | | - features = ops.zeros( |
608 | | - (0, self.feature_size), dtype=self.compute_dtype |
609 | | - ) |
610 | | - mask = ( |
611 | | - ops.zeros((0,), dtype="int32") |
612 | | - if return_attention_mask |
613 | | - else None |
614 | | - ) |
615 | | - return features, mask |
616 | | - |
617 | | - speech = ops.convert_to_tensor( |
618 | | - input_features_list[0], dtype=self.compute_dtype |
| 618 | + mask = ( |
| 619 | + ops.zeros((0, 0) if is_batched else (0,), dtype="int32") |
| 620 | + if return_attention_mask |
| 621 | + else None |
619 | 622 | ) |
620 | | - if return_attention_mask: |
621 | | - mask = ops.convert_to_tensor( |
622 | | - attention_mask_list[0], dtype="int32" |
623 | | - ) |
624 | | - else: |
625 | | - mask = None |
626 | | - features, feature_mask = self._extract_spectrogram(speech, mask) |
627 | | - features = ops.reshape(features, (-1, self.feature_size)) |
| 623 | + return features, mask |
628 | 624 |
|
629 | | - if return_attention_mask: |
630 | | - if feature_mask is None: |
631 | | - feature_mask = ops.ones( |
632 | | - (ops.shape(features)[0],), dtype="int32" |
633 | | - ) |
634 | | - else: |
635 | | - feature_mask = ops.reshape(feature_mask, (-1,)) |
636 | | - feature_mask = ops.cast(feature_mask, "int32") |
637 | | - else: |
638 | | - feature_mask = None |
639 | | - return features, feature_mask |
640 | | - |
641 | | - def process_one_audio(speech): |
642 | | - speech = ops.reshape(speech, (-1,)) |
643 | | - speech = ops.cast(speech, self.compute_dtype) |
644 | | - speech_batched = ops.expand_dims(speech, axis=0) |
645 | | - speech_length = ops.shape(speech_batched)[1] |
646 | | - speech_mask = ops.ones((1, speech_length), dtype="int32") |
647 | | - features, feature_mask = self._extract_spectrogram( |
648 | | - speech_batched, speech_mask |
| 625 | + # Stack into tensors |
| 626 | + padded_speech = ops.convert_to_tensor( |
| 627 | + np.stack(input_features_list, axis=0), dtype=self.compute_dtype |
| 628 | + ) |
| 629 | + padded_mask = ( |
| 630 | + ops.convert_to_tensor( |
| 631 | + np.stack(attention_mask_list, axis=0), dtype="int32" |
649 | 632 | ) |
650 | | - features = ops.reshape(features, (-1, self.feature_size)) |
651 | | - features = ops.cast(features, self.compute_dtype) |
652 | | - if feature_mask is None: |
653 | | - num_frames = ops.shape(features)[0] |
654 | | - feature_mask = ops.ones((num_frames,), dtype="int32") |
655 | | - else: |
656 | | - feature_mask = ops.reshape(feature_mask, (-1,)) |
657 | | - feature_mask = ops.cast(feature_mask, "int32") |
658 | | - return features, feature_mask |
| 633 | + if return_attention_mask |
| 634 | + else None |
| 635 | + ) |
| 636 | + |
| 637 | + # If unbatched (1D), squeeze the batch dimension |
| 638 | + if not is_batched: |
| 639 | + padded_speech = ops.squeeze(padded_speech, axis=0) |
| 640 | + if padded_mask is not None: |
| 641 | + padded_mask = ops.squeeze(padded_mask, axis=0) |
659 | 642 |
|
660 | | - input_features, input_features_mask = tf.map_fn( |
661 | | - process_one_audio, |
662 | | - raw_speech_tensor, |
663 | | - fn_output_signature=( |
664 | | - tf.TensorSpec( |
665 | | - shape=(None, self.feature_size), |
666 | | - dtype=tf.as_dtype(self.compute_dtype), |
667 | | - ), |
668 | | - tf.TensorSpec(shape=(None,), dtype=tf.int32), |
669 | | - ), |
| 643 | + # Extract spectrograms (natively supports 1D and 2D with Keras ops) |
| 644 | + features, feature_mask = self._extract_spectrogram( |
| 645 | + padded_speech, padded_mask |
670 | 646 | ) |
671 | | - return input_features, input_features_mask |
| 647 | + return features, feature_mask |
672 | 648 |
|
673 | 649 | def get_config(self): |
674 | 650 | config = super().get_config() |
|
0 commit comments