commit 2928d242a931d9e51e3331f4eac875599753c4dc
parent 8a631bcf96cf74dd823565f3b10ac682b7230b73
Author: Steven Atkinson <[email protected]>
Date: Thu, 16 Mar 2023 22:32:33 -0500
Models compute their output level (#135)
Implement BaseNet._loudness()
Diffstat:
5 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
@@ -0,0 +1 @@
+include nam/models/_resources/loudness_input.wav
diff --git a/nam/models/_base.py b/nam/models/_base.py
@@ -2,8 +2,15 @@
# Created Date: Tuesday February 8th 2022
# Author: Steven Atkinson ([email protected])
+"""
+The foundation of the model without the PyTorch Lightning attributes (losses, training
+steps)
+"""
+
import abc
import math
+import pkg_resources
+from pathlib import Path
from typing import Any, Optional, Tuple
import numpy as np
@@ -11,7 +18,7 @@ import torch
import torch.nn as nn
from .._core import InitializableFromConfig
-from ..data import REQUIRED_RATE
+from ..data import REQUIRED_RATE, wav_to_tensor
from ._exportable import Exportable
@@ -31,6 +38,21 @@ class _Base(nn.Module, InitializableFromConfig, Exportable):
def forward(self, *args, **kwargs) -> torch.Tensor:
pass
+ def _loudness(self, gain: float=1.0) -> float:
+ """
+ How loud is this model when given a standardized input?
+ In dB
+
+ :param gain: Multiplies input signal
+ """
+ x = wav_to_tensor(pkg_resources.resource_filename("nam", "models/_resources/loudness_input.wav"))
+ y = self._at_nominal_settings(gain * x)
+ return 10.0 * torch.log10(torch.mean(torch.square(y))).item()
+
+ def _at_nominal_settings(self, x: torch.Tensor) -> torch.Tensor:
+ # parametric?...
+ raise NotImplementedError()
+
@abc.abstractmethod
def _forward(self, *args) -> torch.Tensor:
"""
@@ -65,7 +87,7 @@ class _Base(nn.Module, InitializableFromConfig, Exportable):
x.detach().cpu().numpy(),
self(*args, x, pad_start=True).detach().cpu().numpy()
)
-
+
class BaseNet(_Base):
def forward(self, x: torch.Tensor, pad_start: Optional[bool] = None):
@@ -79,6 +101,9 @@ class BaseNet(_Base):
if scalar:
y = y[0]
return y
+
+ def _at_nominal_settings(self, x: torch.Tensor) -> torch.Tensor:
+ return self(x)
@abc.abstractmethod
def _forward(self, x: torch.Tensor) -> torch.Tensor:
diff --git a/nam/models/_resources/loudness_input.wav b/nam/models/_resources/loudness_input.wav
Binary files differ.
diff --git a/setup.py b/setup.py
@@ -31,6 +31,7 @@ setup(
url="https://github.com/sdatkinson/",
install_requires=requirements,
packages=find_packages(),
+ include_package_data=True,
entry_points={
'console_scripts': [
'nam = nam.train.gui:run',
diff --git a/tests/test_nam/test_models/test_base.py b/tests/test_nam/test_models/test_base.py
@@ -0,0 +1,52 @@
+# File: test_base.py
+# Created Date: Thursday March 16th 2023
+# Author: Steven Atkinson ([email protected])
+
+import math
+from pathlib import Path
+
+import numpy as np
+import pytest
+import torch
+
+from nam.models._base import BaseNet
+
+def test_loudness():
+ class C(BaseNet):
+ def __init__(self, gain: float, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.gain = gain
+
+ @property
+ def pad_start_default(self) -> bool:
+ return True
+
+ @property
+ def receptive_field(self) -> int:
+ return 1
+
+ def export_cpp_header(self, filename: Path):
+ pass
+
+ def _export_config(self):
+ pass
+
+ def _export_weights(self) -> np.ndarray:
+ pass
+
+ def _forward(self, x: torch.Tensor) -> torch.Tensor:
+ return self.gain * x
+
+ obj = C(1.0)
+ y = obj._loudness()
+ obj.gain = 2.0
+ y2 = obj._loudness()
+ assert isinstance(y, float)
+ # 2x louder = +6dB
+ assert y2 == pytest.approx(y + 20.0 * math.log10(2.0))
+
+
+
+
+if __name__ == "__main__":
+ pytest.main()
+\ No newline at end of file