Skip to content

Commit dca93c2

Browse files
marialyucopybara-github
authored andcommitted
Add support for multi-dimensional signals in SNR computation
The SNR function now reshapes inputs with more than two dimensions, assuming the first dimension is the batch dimension, to compute SNR across all signal dimensions. This allows handling inputs like images or multi-channel audio. PiperOrigin-RevId: 899078362
1 parent 862d090 commit dca93c2

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,15 @@ dev = [
4545
"jax[cpu]==0.6.2",
4646
"jax_tpu_embedding==0.1.0.dev20250618",
4747
"keras-hub",
48+
"tokenizers",
4849
"keras-rs>=0.2.1",
4950
"nltk>=3.9.1",
5051
"pytest>=8.4.1",
5152
"Pillow>=9.0.0",
5253
"protobuf>=5.29.5",
5354
"rouge-score>=0.1.2",
5455
"scikit-learn>=1.7.1",
56+
"sentencepiece",
5557
"tensorflow",
5658
"torchmetrics>=1.8.1",
5759
]

src/metrax/audio_metrics.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from metrax import base
2121

2222

23+
# TODO(jiwonshin): Move SNR class out of audio metrics since now it can be used
24+
# for image data as well.
2325
@flax.struct.dataclass
2426
class SNR(base.Average):
2527
r"""SNR (Signal-to-Noise Ratio) Metric for audio.
@@ -55,6 +57,13 @@ def _calculate_snr(
5557
) -> jax.Array:
5658
"""Computes SNR (Signal-to-Noise Ratio) values for a batch of audio signals.
5759
60+
If the input has more than 2 dimensions, it is assumed that the first
61+
dimension is the batch dimension and all others are signal dimensions. The
62+
input is then reshaped to (batch, signal_dimensions) to compute the SNR over
63+
all signal dimensions for each example in the batch. E.g. image data of
64+
shape (batch, H, W, C) is reshaped to (batch, H * W * C) to compute the SNR
65+
for each image in the batch.
66+
5867
Args:
5968
preds: The estimated or predicted audio signal. JAX Array.
6069
target: The ground truth audio signal. JAX Array.
@@ -71,6 +80,10 @@ def _calculate_snr(
7180
f' {target.shape}'
7281
)
7382

83+
if preds.ndim > 2:
84+
target = jnp.reshape(target, (target.shape[0], -1))
85+
preds = jnp.reshape(preds, (preds.shape[0], -1))
86+
7487
target_processed, preds_processed = jax.lax.cond(
7588
zero_mean,
7689
lambda t, p: (

src/metrax/audio_metrics_test.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
"""Tests for metrax image metrics."""
15+
"""Tests for metrax audio metrics."""
1616

1717
import os
1818

1919
os.environ['KERAS_BACKEND'] = 'jax'
2020

21-
from absl.testing import absltest
21+
from absl.testing import absltest # pylint: disable=g-import-not-at-top
2222
from absl.testing import parameterized
2323
import jax.numpy as jnp
2424
import metrax
@@ -43,6 +43,13 @@
4343
AUDIO_PREDS_2D_NOISY = (
4444
AUDIO_TARGET_2D + 0.5 * np.random.randn(*AUDIO_SHAPE_2D)
4545
).astype(np.float32)
46+
# 3D batch of signals
47+
AUDIO_SHAPE_3D = (2, 3, 100)
48+
AUDIO_TARGET_3D = (np.random.randn(*AUDIO_SHAPE_3D) * 5.0).astype(np.float32)
49+
AUDIO_PREDS_3D_NOISY = (
50+
AUDIO_TARGET_3D + 0.5 * np.random.randn(*AUDIO_SHAPE_3D)
51+
).astype(np.float32)
52+
4653
# Target and preds are all zeros.
4754
AUDIO_SHAPE_ZEROS = (100,)
4855
AUDIO_TARGET_ZEROS = np.zeros(AUDIO_SHAPE_ZEROS).astype(np.float32)
@@ -88,6 +95,18 @@ class AudioMetricsTest(parameterized.TestCase):
8895
AUDIO_PREDS_2D_NOISY,
8996
True,
9097
),
98+
(
99+
'snr_3d_noisy_false_zero_mean',
100+
AUDIO_TARGET_3D,
101+
AUDIO_PREDS_3D_NOISY,
102+
False,
103+
),
104+
(
105+
'snr_3d_noisy_true_zero_mean',
106+
AUDIO_TARGET_3D,
107+
AUDIO_PREDS_3D_NOISY,
108+
True,
109+
),
91110
(
92111
'snr_zeros_false_zero_mean',
93112
AUDIO_TARGET_ZEROS,
@@ -110,6 +129,10 @@ def test_snr(
110129
)
111130
metrax_snr_result = metrax_snr_metric.compute()
112131

132+
if preds_np.ndim > 2:
133+
preds_np = preds_np.reshape(preds_np.shape[0], -1)
134+
target_np = target_np.reshape(target_np.shape[0], -1)
135+
113136
torchmetrics_snr_result = (
114137
tm_snr.signal_noise_ratio(
115138
preds=torch.from_numpy(preds_np),

0 commit comments

Comments
 (0)