From 40cf01acfe8b89cf3bf5e4306abc5247d12cf9a6 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:50 -0300 Subject: [PATCH 01/76] Add cosine window --- aten/src/ATen/native/TensorFactories.cpp | 88 +++++++++++++++++++++ aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 19 +++++ aten/src/ATen/native/native_functions.yaml | 10 +++ docs/source/jit_unsupported.rst | 1 + docs/source/torch.rst | 1 + 5 files changed, 119 insertions(+) diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index 2e01f7e8699ad..eade3af0ef798 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -1391,6 +1391,94 @@ Tensor kaiser_window( return periodic ? window.narrow(0, 0, window_length - 1) : window; } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cheb_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tensor cheb_window(int64_t window_length, + c10::optional dtype, + c10::optional layout, + c10::optional device, + c10::optional pin_memory) { + return native::kaiser_window( + window_length, + /*periodic=*/true, + /*beta=*/12.0, + dtype, + layout, + device, + pin_memory); +} + +//Tensor cheb_window(int64_t window_length, +// bool periodic, +// double attenuation, +// c10::optional dtype_opt, +// c10::optional layout, +// c10::optional device, +// c10::optional pin_memory) { +// +// ScalarType dtype = c10::dtype_or_default(dtype_opt); +// TensorOptions options = TensorOptions().dtype(dtype).layout(layout).device(device).pinned_memory(pin_memory); +// +// window_function_checks("cheb_window", options, window_length); +// +// // short-circuit for `meta`. +// if (device == kMeta) { +// return at::empty({window_length}, options); +// } +// +// if (window_length == 0) { +// return at::empty({0}, options); +// } +// if (window_length == 1) { +// return at::ones({1}, options); +// } +// if (periodic) { +// window_length += 1; +// } +// auto initial = at::arange(window_length, options); +// auto window = at::empty(window_length, options); +// auto iter = TensorIterator::unary_op(window, initial); +// cheb_window_stub(iter.device_type(), iter, window_length, attenuation); +// return periodic ? window.narrow(0, 0, window_length - 1) : window; +//} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ cosine_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tensor cosine_window(int64_t window_length, + c10::optional dtype, + c10::optional layout, + c10::optional device, + c10::optional pin_memory) { + return native::cosine_window( + window_length, /*periodic=*/true, dtype, layout, device, pin_memory); +} + +Tensor cosine_window( + int64_t window_length, + bool periodic, + c10::optional dtype_opt, + c10::optional layout, + c10::optional device, + c10::optional pin_memory) { + // See [Note: hacky wrapper removal for TensorOptions] + ScalarType dtype = c10::dtype_or_default(dtype_opt); + TensorOptions options = TensorOptions().dtype(dtype).layout(layout).device(device).pinned_memory(pin_memory); + + window_function_checks("cosine_window", options, window_length); + if (window_length == 0) { + return at::empty({0}, options); + } + if (window_length == 1) { + return native::ones({1}, dtype, layout, device, pin_memory); + } + if (periodic) { + window_length += 1; + } + auto window = native::arange(window_length, dtype, layout, device, pin_memory) + .add(0.5).mul_(c10::pi).mul_(static_cast(1.0 / window_length)).sin_(); + return periodic ? window.narrow(0, 0, window_length - 1) : window; +} + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ vandermonde_matrix ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index 8a0534fd3da5f..51d891edb72e0 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -466,6 +466,25 @@ static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length }); } +//static void cheb_window_kernel(TensorIteratorBase& iter, int64_t window_length, double attenuation){ +// AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "cheb_window_cpu", [&](){ +// const int64_t n = window_length - 1; +// const scalar_t beta = static_cast(std::cosh(1.0 / n * std::acosh(std::pow(10, attenuation / 20.0)))); +// cpu_kernel(iter, [=](scalar_t a){ +// auto x = beta * std::cos(c10::pi * a / window_length); +// return chebyshev_polynomial_t_forward(x, n) / std::pow(10, att / 20.0); +// }); +// }); +//} + +//static void cosine_window_kernel(TensorIteratorBase& iter, int64_t window_length) { +// AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "cosine_window_cpu", [&](){ +// cpu_kernel(iter, [=](scalar_t a){ +// return std::sin(c10::pi / window_length * (a + 0.5)); +// }); +// }); +//} + void rsqrt_kernel(TensorIteratorBase& iter) { AT_DISPATCH_FLOATING_AND_COMPLEX_TYPES_AND1(kBFloat16, iter.common_dtype(), "rsqrt_cpu", [&] { cpu_kernel_vec( diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index 3452e5f6a3088..190e18c0a7935 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -2567,6 +2567,16 @@ CUDA: grid_sampler_3d_backward_cuda autogen: grid_sampler_3d_backward.out +- func: cosine_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor + dispatch: + CompositeExplicitAutograd: cosine_window + autogen: cosine_window.out + +- func: cosine_window.periodic(int window_length, bool periodic, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor + dispatch: + CompositeExplicitAutograd: cosine_window + autogen: cosine_window.periodic_out + - func: hann_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor dispatch: CompositeExplicitAutograd: hann_window diff --git a/docs/source/jit_unsupported.rst b/docs/source/jit_unsupported.rst index 7368abad1e300..a143825260533 100644 --- a/docs/source/jit_unsupported.rst +++ b/docs/source/jit_unsupported.rst @@ -50,6 +50,7 @@ argument, except for `torch.tensor`. This covers the following ops: * :func:`torch.eye` * :func:`torch.full` * :func:`torch.full_like` + * :func:`torch.cosine_window` * :func:`torch.hamming_window` * :func:`torch.hann_window` * :func:`torch.linspace` diff --git a/docs/source/torch.rst b/docs/source/torch.rst index 0f7a3397e5b28..02b9705ee37e3 100644 --- a/docs/source/torch.rst +++ b/docs/source/torch.rst @@ -475,6 +475,7 @@ Spectral Ops hamming_window hann_window kaiser_window + cosine_window Other Operations From 241037eb7b9a9cecf47fa6dcd2b7eaf74f273b94 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:51 -0300 Subject: [PATCH 02/76] Add chebyshev window --- aten/src/ATen/native/SpectralOps.cpp | 2 +- aten/src/ATen/native/SpectralOps.h | 19 ++++ aten/src/ATen/native/TensorFactories.cpp | 112 +++++++++++++------- aten/src/ATen/native/UnaryOps.h | 1 + aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 31 +++--- aten/src/ATen/native/native_functions.yaml | 15 +++ 6 files changed, 123 insertions(+), 57 deletions(-) create mode 100644 aten/src/ATen/native/SpectralOps.h diff --git a/aten/src/ATen/native/SpectralOps.cpp b/aten/src/ATen/native/SpectralOps.cpp index c2e5bda454ea4..e9b8d24890678 100644 --- a/aten/src/ATen/native/SpectralOps.cpp +++ b/aten/src/ATen/native/SpectralOps.cpp @@ -1223,7 +1223,7 @@ void _fft_fill_with_conjugate_symmetry_(const Tensor& input, IntArrayRef dim_) { fft_fill_with_conjugate_symmetry_stub( input.device().type(), input.scalar_type(), mirror_dims, signal_half_sizes, in_strides, in_data, out_strides, out_data); -} +} // namespace DEFINE_DISPATCH(fft_fill_with_conjugate_symmetry_stub); diff --git a/aten/src/ATen/native/SpectralOps.h b/aten/src/ATen/native/SpectralOps.h new file mode 100644 index 0000000000000..aa73327100d19 --- /dev/null +++ b/aten/src/ATen/native/SpectralOps.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +namespace at { namespace native { + +Tensor fft_ifft(const Tensor& self, c10::optional n, int64_t dim, + c10::optional norm); + +Tensor& fft_ifft_out(const Tensor& self, c10::optional n, + int64_t dim, c10::optional norm, + Tensor& out); + +Tensor fft_fft(const Tensor& self, c10::optional n, int64_t dim, + c10::optional norm); + +}} // at::native diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index eade3af0ef798..c686ec7adc10a 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1391,56 +1392,91 @@ Tensor kaiser_window( return periodic ? window.narrow(0, 0, window_length - 1) : window; } -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cheb_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ chebyshev_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Tensor cheb_window(int64_t window_length, +Tensor chebyshev_window(int64_t window_length, c10::optional dtype, c10::optional layout, c10::optional device, c10::optional pin_memory) { - return native::kaiser_window( + return native::chebyshev_window( window_length, /*periodic=*/true, - /*beta=*/12.0, dtype, layout, device, pin_memory); } -//Tensor cheb_window(int64_t window_length, -// bool periodic, -// double attenuation, -// c10::optional dtype_opt, -// c10::optional layout, -// c10::optional device, -// c10::optional pin_memory) { -// -// ScalarType dtype = c10::dtype_or_default(dtype_opt); -// TensorOptions options = TensorOptions().dtype(dtype).layout(layout).device(device).pinned_memory(pin_memory); -// -// window_function_checks("cheb_window", options, window_length); -// -// // short-circuit for `meta`. -// if (device == kMeta) { -// return at::empty({window_length}, options); -// } -// -// if (window_length == 0) { -// return at::empty({0}, options); -// } -// if (window_length == 1) { -// return at::ones({1}, options); -// } -// if (periodic) { -// window_length += 1; -// } -// auto initial = at::arange(window_length, options); -// auto window = at::empty(window_length, options); -// auto iter = TensorIterator::unary_op(window, initial); -// cheb_window_stub(iter.device_type(), iter, window_length, attenuation); -// return periodic ? window.narrow(0, 0, window_length - 1) : window; -//} +Tensor chebyshev_window(int64_t window_length, + bool periodic, + c10::optional dtype, + c10::optional layout, + c10::optional device, + c10::optional pin_memory) { + return native::chebyshev_window( + window_length, + periodic, + /*attenuation=*/40, + dtype, + layout, + device, + pin_memory); +} + +Tensor chebyshev_window(int64_t window_length, + bool periodic, + double attenuation, + c10::optional dtype_opt, + c10::optional layout, + c10::optional device, + c10::optional pin_memory) { + ScalarType dtype = c10::dtype_or_default(dtype_opt); + TensorOptions options = TensorOptions() + .dtype(dtype) + .layout(layout) + .device(device) + .pinned_memory(pin_memory); + + window_function_checks("chebyshev_window", options, window_length); + + // short-circuit for `meta`. + if (device == kMeta) { + return at::empty({window_length}, options); + } + + if (window_length == 0) { + return at::empty({0}, options); + } + if (window_length == 1) { + return at::ones({1}, options); + } + if (periodic) { + window_length += 1; + } + + auto initial = at::arange(window_length, options); + auto window = at::empty(window_length, options); + auto iter = TensorIterator::unary_op(window, initial); + chebyshev_window_stub(iter.device_type(), iter, window_length, attenuation); + + if (window_length % 2 != 0) { + window = at::real(at::native::fft_ifft(window, window_length, 0, "backward")); + auto n = (window_length + 1) / 2; + window = window.narrow(0, 0, n); + window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window}); + } else { + auto j = c10::Scalar(c10::complex(0, 1)); + auto W = (at::arange(window_length, options).mul_(c10::pi / window_length) * j).exp_().mul_(window); + window = at::real(at::native::fft_fft(W, window_length, 0, "backward")); + auto n = (window_length / 2) + 1; + window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window.narrow(0, 1, n-1)}); + } + + window.div_(window.max()); + + return periodic ? window.narrow(0, 0, window_length - 1) : window; +} // ~~~~~~~~~~~~~~~~~~~~~~~~~~ cosine_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1682,6 +1718,8 @@ Tensor rand( DEFINE_DISPATCH(kaiser_window_stub); +DEFINE_DISPATCH(chebyshev_window_stub); + } // namespace native } // namespace at diff --git a/aten/src/ATen/native/UnaryOps.h b/aten/src/ATen/native/UnaryOps.h index 103e522fa35db..13f2bc9bbfab6 100644 --- a/aten/src/ATen/native/UnaryOps.h +++ b/aten/src/ATen/native/UnaryOps.h @@ -97,6 +97,7 @@ DECLARE_DISPATCH(void(*)(TensorIteratorBase&, c10::optional), random_ DECLARE_DISPATCH(void(*)(TensorIteratorBase&, c10::optional), random_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t, const double), kaiser_window_stub); +DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t, const double), chebyshev_window_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t), polygamma_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const Scalar& a, const Scalar& b), clamp_stub); DECLARE_DISPATCH( diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index 51d891edb72e0..45686dee4f123 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -457,7 +457,7 @@ static void nan_to_num_kernel( }); } -static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length, double beta){ +static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length, double beta) { AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "kaiser_window_cpu", [&](){ const scalar_t alpha = static_cast((window_length - 1) / 2.0); cpu_kernel(iter, [=](scalar_t a){ @@ -466,24 +466,16 @@ static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length }); } -//static void cheb_window_kernel(TensorIteratorBase& iter, int64_t window_length, double attenuation){ -// AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "cheb_window_cpu", [&](){ -// const int64_t n = window_length - 1; -// const scalar_t beta = static_cast(std::cosh(1.0 / n * std::acosh(std::pow(10, attenuation / 20.0)))); -// cpu_kernel(iter, [=](scalar_t a){ -// auto x = beta * std::cos(c10::pi * a / window_length); -// return chebyshev_polynomial_t_forward(x, n) / std::pow(10, att / 20.0); -// }); -// }); -//} - -//static void cosine_window_kernel(TensorIteratorBase& iter, int64_t window_length) { -// AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "cosine_window_cpu", [&](){ -// cpu_kernel(iter, [=](scalar_t a){ -// return std::sin(c10::pi / window_length * (a + 0.5)); -// }); -// }); -//} +static void chebyshev_window_kernel(TensorIteratorBase& iter, int64_t window_length, double attenuation) { + AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "chebyshev_window_cpu", [&](){ + const int64_t n = window_length - 1; + const scalar_t beta = static_cast(std::cosh(1.0 / n * std::acosh(std::pow(10, attenuation / 20.0)))); + cpu_kernel(iter, [=](scalar_t a){ + auto x = beta * static_cast(std::cos(c10::pi * a / window_length)); + return static_cast(chebyshev_polynomial_t_forward(x, n) / std::pow(10, attenuation / 20.0)); + }); + }); +} void rsqrt_kernel(TensorIteratorBase& iter) { AT_DISPATCH_FLOATING_AND_COMPLEX_TYPES_AND1(kBFloat16, iter.common_dtype(), "rsqrt_cpu", [&] { @@ -754,6 +746,7 @@ REGISTER_DISPATCH(digamma_stub, &CPU_CAPABILITY::digamma_kernel); REGISTER_DISPATCH(trigamma_stub, &CPU_CAPABILITY::trigamma_kernel); REGISTER_DISPATCH(polygamma_stub, &CPU_CAPABILITY::polygamma_kernel); REGISTER_DISPATCH(kaiser_window_stub, &CPU_CAPABILITY::kaiser_window_kernel); +REGISTER_DISPATCH(chebyshev_window_stub, &CPU_CAPABILITY::chebyshev_window_kernel); REGISTER_DISPATCH(special_entr_stub, &CPU_CAPABILITY::entr_kernel); REGISTER_DISPATCH(frexp_stub, &CPU_CAPABILITY::frexp_kernel); REGISTER_DISPATCH(special_i0e_stub, &CPU_CAPABILITY::i0e_kernel); diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index 190e18c0a7935..9a6a205b50946 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -2622,6 +2622,21 @@ CompositeExplicitAutograd: kaiser_window autogen: kaiser_window.beta_out +- func: chebyshev_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor + dispatch: + CompositeExplicitAutograd: chebyshev_window + autogen: chebyshev_window.out + +- func: chebyshev_window.periodic(int window_length, bool periodic, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor + dispatch: + CompositeExplicitAutograd: chebyshev_window + autogen: chebyshev_window.periodic_out + +- func: chebyshev_window.periodic_attenuation(int window_length, bool periodic, float attenuation, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor + dispatch: + CompositeExplicitAutograd: chebyshev_window + autogen: chebyshev_window.periodic_attenuation_out + - func: hinge_embedding_loss(Tensor self, Tensor target, float margin=1.0, int reduction=Mean) -> Tensor - func: group_norm(Tensor input, int num_groups, Tensor? weight=None, Tensor? bias=None, float eps=1e-05, bool cudnn_enabled=True) -> Tensor From d46d2277795f9543192cbd16d3fbc6373f81157b Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:51 -0300 Subject: [PATCH 03/76] Cast int --- aten/src/ATen/native/TensorFactories.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index c686ec7adc10a..0e5ec9fa03d72 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -1461,15 +1461,15 @@ Tensor chebyshev_window(int64_t window_length, chebyshev_window_stub(iter.device_type(), iter, window_length, attenuation); if (window_length % 2 != 0) { - window = at::real(at::native::fft_ifft(window, window_length, 0, "backward")); - auto n = (window_length + 1) / 2; + window = at::real(at::native::fft_fft(window, window_length, 0, "backward")); + auto n = static_cast((window_length + 1) / 2); window = window.narrow(0, 0, n); window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window}); } else { auto j = c10::Scalar(c10::complex(0, 1)); auto W = (at::arange(window_length, options).mul_(c10::pi / window_length) * j).exp_().mul_(window); window = at::real(at::native::fft_fft(W, window_length, 0, "backward")); - auto n = (window_length / 2) + 1; + auto n = static_cast((window_length / 2) + 1); window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window.narrow(0, 1, n-1)}); } From 56aebc712139fc66c4e8f8c3fbdba2558a9d910c Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:52 -0300 Subject: [PATCH 04/76] Add signal module and a few windows --- test/test_tensor_creation_ops.py | 11 ++- torch/signal/__init__.py | 7 ++ torch/signal/windows/__init__.py | 7 ++ torch/signal/windows/windows.py | 153 +++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 torch/signal/__init__.py create mode 100644 torch/signal/windows/__init__.py create mode 100644 torch/signal/windows/windows.py diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index aab2645249698..dc6df257d3888 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2634,7 +2634,7 @@ def test_tensor_ctor_device_inference(self, device): def _test_signal_window_functions(self, name, dtype, device, **kwargs): import scipy.signal as signal - torch_method = getattr(torch, name + '_window') + torch_method = getattr(torch.signal.windows, name + '_window') if not dtype.is_floating_point: with self.assertRaisesRegex(RuntimeError, r'floating point'): torch_method(3, dtype=dtype) @@ -2668,6 +2668,15 @@ def test_kaiser_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('kaiser', dtype, device, beta=random.random() * 30) + @onlyNativeDeviceTypes + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @unittest.skipIf(not TEST_SCIPY, "Scipy not found") + @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) + @dtypes(torch.float, torch.double, torch.long) + def test_cosine_window(self, device, dtype): + for num_test in range(50): + self._test_signal_window_functions('cosine', dtype, device) + def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function shapes = [(5, 0, 1), (0,), (0, 0, 1, 0, 2, 0, 0)] diff --git a/torch/signal/__init__.py b/torch/signal/__init__.py new file mode 100644 index 0000000000000..8de19cb0f6482 --- /dev/null +++ b/torch/signal/__init__.py @@ -0,0 +1,7 @@ +from .windows import cosine_window, exponential_window, chebyshev_window + +__all__ = [ + 'cosine_window', + 'exponential_window', + 'chebyshev_window' +] diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py new file mode 100644 index 0000000000000..8de19cb0f6482 --- /dev/null +++ b/torch/signal/windows/__init__.py @@ -0,0 +1,7 @@ +from .windows import cosine_window, exponential_window, chebyshev_window + +__all__ = [ + 'cosine_window', + 'exponential_window', + 'chebyshev_window' +] diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py new file mode 100644 index 0000000000000..e423b0bb6a71a --- /dev/null +++ b/torch/signal/windows/windows.py @@ -0,0 +1,153 @@ +import torch + +import numpy as np + +from torch import Tensor +from torch.types import _dtype, _device, _layout +from torch.fft import fft + +__all__ = ['cosine_window'] + + +def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout, device: _device): + def is_floating_type(t: _dtype) -> bool: + return t == torch.float32 or t == torch.bfloat16 or t == torch.float64 or t == torch.float16 + + def is_complex_type(t: _dtype) -> bool: + return t == torch.complex64 or t == torch.complex128 or t == torch.complex32 + + if window_length < 0: + raise RuntimeError(f'{function_name} requires non-negative window_length, got window_length: {window_length}') + if layout is torch.sparse: + raise RuntimeError(f'{function_name} is not implemented for sparse types, got layout: {layout}') + if not is_floating_type(dtype) and not is_complex_type(dtype): + raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') + + +def chebyshev_window(window_length: int, + attenuation: float, + periodic: bool = True, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None) -> Tensor: + _window_function_checks('chebyshev_window', window_length, dtype, layout, device) + + if window_length == 0: + return torch.empty((0,), dtype=dtype, layout=layout, device=device) + + if window_length == 1: + return torch.ones((1,), dtype=dtype, layout=layout, device=device) + + if not periodic: + window_length += 1 + + k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) + + order = window_length - 1 + beta = np.cosh(1.0 / order * np.arccosh(np.power(10, attenuation / 20.0))) + + x = beta * torch.cos(torch.pi * k / window_length) + window = torch.special.chebyshev_polynomial_t(x, order) / np.power(10, attenuation / 20.0) + + if window_length % 2 != 0: + window = torch.real(fft(window)) + n = (window_length + 1) // 2 + window = torch.concat((torch.flip(window[1:n], (0,)), window[:n])) + else: + window = window * torch.exp(1.j * torch.pi / window_length * torch.arange(window_length)) + window = torch.real(fft(window)) + n = window_length // 2 + 1 + window = torch.concat((torch.flip(window[1:n], (0,)), window[1:n])) + + window /= torch.max(window) + + return window if periodic else window[:window_length - 1] + + +def exponential_window(window_length: int, + periodic: bool = True, + center: float = None, + tau: float = 1.0, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None) -> Tensor: + """r + Computes a window with a simple cosine waveform. + + Args: + window_length: + + Keyword args: + {dtype} + {device} + + """ + _window_function_checks('exponential_window', window_length, dtype, layout, device) + + if window_length == 0: + return torch.empty((0,), dtype=dtype, layout=layout, device=device) + + if window_length == 1: + return torch.ones((1,), dtype=dtype, layout=layout, device=device) + + if not periodic: + window_length += 1 + + if periodic and center is not None: + raise ValueError('Center must be \'None\' for periodic equal True') + + if center is None: + center = (window_length - 1) / 2 + + k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) + window = torch.exp(-torch.abs(k - center) / tau) + + return window if periodic else window[:window_length - 1] + + +def cosine_window(window_length: int, + periodic: bool = True, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None) -> Tensor: + """r + Computes a window with a simple cosine waveform. + + The cosine window is also known as the sine window due to the following + equality: + + .. math:: + w(n) = \cos{(\frac{\pi n}{M}) - \frac{\pi}{2})} = \sin{(\frac{\pi n}{M})} + + Where `M + + + Args: + window_length: the length of the output window. In other words, the number of points of the cosine window. + periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, + returns a symmetric window suitable for use in filter design. + + Keyword args: + {dtype} + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only + `torch.strided` (dense layout) is supported. + {device} + {requires_grad} + """ + _window_function_checks('cosine_window', window_length, dtype, layout, device) + + if window_length == 0: + return torch.empty((0,), dtype=dtype, layout=layout, device=device) + + if window_length == 1: + return torch.ones((1,), dtype=dtype, layout=layout, device=device) + + if not periodic: + window_length += 1 + + # k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) + k = np.arange(0, window_length) + window = np.sin(np.pi / window_length * (k + .5)) + window = torch.from_numpy(window) + + return window if periodic else window[:window_length - 1] From 1603573a6509d2a5b5052d88ffe5fb33c7b7756b Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:53 -0300 Subject: [PATCH 05/76] update --- docs/source/signal.windows.rst | 17 ++++ torch/__init__.py | 1 + torch/signal/__init__.py | 4 +- torch/signal/windows/__init__.py | 4 +- torch/signal/windows/windows.py | 161 +++++++++++++++++++------------ 5 files changed, 119 insertions(+), 68 deletions(-) create mode 100644 docs/source/signal.windows.rst diff --git a/docs/source/signal.windows.rst b/docs/source/signal.windows.rst new file mode 100644 index 0000000000000..7261534da739f --- /dev/null +++ b/docs/source/signal.windows.rst @@ -0,0 +1,17 @@ +.. role:: hidden + :class: hidden-section + +torch.signal.windows +============= + +The torch.signal.windows module, modeled after SciPy's `special `_ module. + +.. automodule:: torch.signal.windows +.. currentmodule:: torch.signal.windows + +Functions +----------------------- + +.. autofunction:: cosine_window +.. autofunction:: exponential_window +.. autofunction:: gaussian_window diff --git a/torch/__init__.py b/torch/__init__.py index 92155a498feb6..4464fa853ae91 100644 --- a/torch/__init__.py +++ b/torch/__init__.py @@ -846,6 +846,7 @@ def _assert(condition, message): from torch import futures as futures from torch import nested as nested from torch import nn as nn +from torch.signal import windows as windows from torch import optim as optim import torch.optim._multi_tensor from torch import multiprocessing as multiprocessing diff --git a/torch/signal/__init__.py b/torch/signal/__init__.py index 8de19cb0f6482..f79d655133999 100644 --- a/torch/signal/__init__.py +++ b/torch/signal/__init__.py @@ -1,7 +1,7 @@ -from .windows import cosine_window, exponential_window, chebyshev_window +from .windows import cosine_window, exponential_window, gaussian_window __all__ = [ 'cosine_window', 'exponential_window', - 'chebyshev_window' + 'gaussian_window', ] diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 8de19cb0f6482..f79d655133999 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -1,7 +1,7 @@ -from .windows import cosine_window, exponential_window, chebyshev_window +from .windows import cosine_window, exponential_window, gaussian_window __all__ = [ 'cosine_window', 'exponential_window', - 'chebyshev_window' + 'gaussian_window', ] diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index e423b0bb6a71a..832aa4fd4cd45 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -6,10 +6,14 @@ from torch.types import _dtype, _device, _layout from torch.fft import fft -__all__ = ['cosine_window'] +__all__ = [ + 'cosine_window', + 'exponential_window', + 'gaussian_window', +] -def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout, device: _device): +def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout): def is_floating_type(t: _dtype) -> bool: return t == torch.float32 or t == torch.bfloat16 or t == torch.float64 or t == torch.float16 @@ -17,80 +21,58 @@ def is_complex_type(t: _dtype) -> bool: return t == torch.complex64 or t == torch.complex128 or t == torch.complex32 if window_length < 0: - raise RuntimeError(f'{function_name} requires non-negative window_length, got window_length: {window_length}') - if layout is torch.sparse: - raise RuntimeError(f'{function_name} is not implemented for sparse types, got layout: {layout}') + raise RuntimeError(f'{function_name} requires non-negative window_length, got window_length={window_length}') + if layout is torch.sparse_coo: + raise RuntimeError(f'{function_name} is not implemented for sparse types, got: {layout}') if not is_floating_type(dtype) and not is_complex_type(dtype): raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') -def chebyshev_window(window_length: int, - attenuation: float, - periodic: bool = True, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None) -> Tensor: - _window_function_checks('chebyshev_window', window_length, dtype, layout, device) - - if window_length == 0: - return torch.empty((0,), dtype=dtype, layout=layout, device=device) - - if window_length == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device) - - if not periodic: - window_length += 1 - - k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) - - order = window_length - 1 - beta = np.cosh(1.0 / order * np.arccosh(np.power(10, attenuation / 20.0))) - - x = beta * torch.cos(torch.pi * k / window_length) - window = torch.special.chebyshev_polynomial_t(x, order) / np.power(10, attenuation / 20.0) - - if window_length % 2 != 0: - window = torch.real(fft(window)) - n = (window_length + 1) // 2 - window = torch.concat((torch.flip(window[1:n], (0,)), window[:n])) - else: - window = window * torch.exp(1.j * torch.pi / window_length * torch.arange(window_length)) - window = torch.real(fft(window)) - n = window_length // 2 + 1 - window = torch.concat((torch.flip(window[1:n], (0,)), window[1:n])) - - window /= torch.max(window) - - return window if periodic else window[:window_length - 1] - - def exponential_window(window_length: int, periodic: bool = True, center: float = None, tau: float = 1.0, dtype: _dtype = None, layout: _layout = torch.strided, - device: _device = None) -> Tensor: + device: _device = None, + requires_grad: bool = False) -> Tensor: """r - Computes a window with a simple cosine waveform. + Computes a window with an exponential form. The window + is also known as Poisson window. + + The exponential window is defined as follows: + + .. math:: + w(n) = \exp{-\frac{|n - center|}{\tau}} Args: - window_length: + window_length: the length of the output window. In other words, the number of points of the cosine window. + periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, + returns a symmetric window suitable for use in filter design. + center: this value defines where the center of the window will be located. In other words, at which + sample the peak of the window can be found. + tau: the decay value. For `center = 0`, it's suggested to use `tau = -(M - 1) / ln(x)`, if `` is + the fraction of the window remaining at the end. Keyword args: {dtype} + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only + `torch.strided` (dense layout) is supported. {device} - + {requires_grad} """ + if dtype is None: + dtype = torch.get_default_dtype() + _window_function_checks('exponential_window', window_length, dtype, layout, device) if window_length == 0: - return torch.empty((0,), dtype=dtype, layout=layout, device=device) + return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) if window_length == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device) + return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if not periodic: + if periodic: window_length += 1 if periodic and center is not None: @@ -99,17 +81,18 @@ def exponential_window(window_length: int, if center is None: center = (window_length - 1) / 2 - k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) + k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) window = torch.exp(-torch.abs(k - center) / tau) - return window if periodic else window[:window_length - 1] + return window[:-1] if periodic else window def cosine_window(window_length: int, periodic: bool = True, dtype: _dtype = None, layout: _layout = torch.strided, - device: _device = None) -> Tensor: + device: _device = None, + requires_grad: bool = False) -> Tensor: """r Computes a window with a simple cosine waveform. @@ -119,7 +102,7 @@ def cosine_window(window_length: int, .. math:: w(n) = \cos{(\frac{\pi n}{M}) - \frac{\pi}{2})} = \sin{(\frac{\pi n}{M})} - Where `M + Where `M` is the window length. Args: @@ -134,20 +117,70 @@ def cosine_window(window_length: int, {device} {requires_grad} """ + if dtype is None: + dtype = torch.get_default_dtype() + _window_function_checks('cosine_window', window_length, dtype, layout, device) if window_length == 0: - return torch.empty((0,), dtype=dtype, layout=layout, device=device) + return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) if window_length == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device) + return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if not periodic: + if periodic: window_length += 1 - # k = torch.arange(window_length, dtype=dtype, layout=layout, device=device) - k = np.arange(0, window_length) - window = np.sin(np.pi / window_length * (k + .5)) - window = torch.from_numpy(window) + k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + window = torch.sin(torch.pi / window_length * (k + .5)) + return window[:-1] if periodic else window + + +def gaussian_window(window_length: int, + periodic: bool = True, + std: float = 0.5, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None, + requires_grad: bool = False) -> Tensor: + """r + Computes a window with a gaussian waveform. + + The gaussian window is defined as follows: + + .. math:: + w(n) = \exp{-\frac{1}{2}\frac{n}{\sigma}^2} + + Args: + window_length: the length of the output window. In other words, the number of points of the cosine window. + periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, + returns a symmetric window suitable for use in filter design. + std: the standard deviation of the gaussian. It controls how narrow or wide the window is. + + + Keyword args: + {dtype} + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only + `torch.strided` (dense layout) is supported. + {device} + {requires_grad} + """ + if dtype is None: + dtype = torch.get_default_dtype() + + _window_function_checks('cosine_window', window_length, dtype, layout, device) + + if window_length == 0: + return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + + if window_length == 1: + return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + + if periodic: + window_length += 1 - return window if periodic else window[:window_length - 1] + k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + k = k - (window_length - 1.0) / 2.0 + sig2 = 2 * std * std + window = torch.exp(-k ** 2 / sig2) + return window[:-1] if periodic else window From e911e40b6a4a4b15c27f9d8b0d5c14b6d23ec9f1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:53 -0300 Subject: [PATCH 06/76] update --- test/test_tensor_creation_ops.py | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index dc6df257d3888..fe3a76f26c055 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2677,6 +2677,45 @@ def test_cosine_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('cosine', dtype, device) + @onlyNativeDeviceTypes + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @unittest.skipIf(not TEST_SCIPY, "Scipy not found") + @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) + @dtypes(torch.float, torch.double, torch.long) + def test_exponential_window(self, device, dtype): + for num_test in range(50): + self._test_signal_window_functions('exponential', dtype, device) + + @onlyNativeDeviceTypes + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @unittest.skipIf(not TEST_SCIPY, "Scipy not found") + @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) + @dtypes(torch.float, torch.double, torch.long) + def test_gaussian_window(self, device, dtype): + for num_test in range(50): + self._test_signal_window_functions('gaussian', dtype, device, std=random.random() * 30) + + @onlyNativeDeviceTypes + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @unittest.skipIf(not TEST_SCIPY, "Scipy not found") + @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) + @dtypes(torch.float, torch.double) + def test_dummy(self, device, dtype): + from scipy import signal + + NP2TORCH = { + torch.float64: np.float64, + torch.float32: np.float32 + } + + at = 41 + window_length = 100 + w1 = signal.get_window(('chebwin', at), window_length, fftbins=False).astype(NP2TORCH[dtype]) + # w1 = signal.windows.chebwin(100, 100, sym=True).astype(NP2TORCH[dtype]) + w2 = torch.signal.windows.chebyshev_window(window_length, at=at, periodic=False, dtype=dtype, device=device) + + self.assertEqual(w1, w2, exact_dtype=True) + def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function shapes = [(5, 0, 1), (0,), (0, 0, 1, 0, 2, 0, 0)] From e637105c9996950d0aec900081e17a42a907d640 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:54 -0300 Subject: [PATCH 07/76] remove --- aten/src/ATen/native/TensorFactories.cpp | 123 --------------------- aten/src/ATen/native/native_functions.yaml | 10 -- 2 files changed, 133 deletions(-) diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index 0e5ec9fa03d72..3aa475a5035a5 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -1392,129 +1392,6 @@ Tensor kaiser_window( return periodic ? window.narrow(0, 0, window_length - 1) : window; } -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ chebyshev_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Tensor chebyshev_window(int64_t window_length, - c10::optional dtype, - c10::optional layout, - c10::optional device, - c10::optional pin_memory) { - return native::chebyshev_window( - window_length, - /*periodic=*/true, - dtype, - layout, - device, - pin_memory); -} - -Tensor chebyshev_window(int64_t window_length, - bool periodic, - c10::optional dtype, - c10::optional layout, - c10::optional device, - c10::optional pin_memory) { - return native::chebyshev_window( - window_length, - periodic, - /*attenuation=*/40, - dtype, - layout, - device, - pin_memory); -} - -Tensor chebyshev_window(int64_t window_length, - bool periodic, - double attenuation, - c10::optional dtype_opt, - c10::optional layout, - c10::optional device, - c10::optional pin_memory) { - ScalarType dtype = c10::dtype_or_default(dtype_opt); - TensorOptions options = TensorOptions() - .dtype(dtype) - .layout(layout) - .device(device) - .pinned_memory(pin_memory); - - window_function_checks("chebyshev_window", options, window_length); - - // short-circuit for `meta`. - if (device == kMeta) { - return at::empty({window_length}, options); - } - - if (window_length == 0) { - return at::empty({0}, options); - } - if (window_length == 1) { - return at::ones({1}, options); - } - if (periodic) { - window_length += 1; - } - - auto initial = at::arange(window_length, options); - auto window = at::empty(window_length, options); - auto iter = TensorIterator::unary_op(window, initial); - chebyshev_window_stub(iter.device_type(), iter, window_length, attenuation); - - if (window_length % 2 != 0) { - window = at::real(at::native::fft_fft(window, window_length, 0, "backward")); - auto n = static_cast((window_length + 1) / 2); - window = window.narrow(0, 0, n); - window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window}); - } else { - auto j = c10::Scalar(c10::complex(0, 1)); - auto W = (at::arange(window_length, options).mul_(c10::pi / window_length) * j).exp_().mul_(window); - window = at::real(at::native::fft_fft(W, window_length, 0, "backward")); - auto n = static_cast((window_length / 2) + 1); - window = at::cat({at::flip(window.narrow(0, 1, n-1), {0}), window.narrow(0, 1, n-1)}); - } - - window.div_(window.max()); - - return periodic ? window.narrow(0, 0, window_length - 1) : window; -} - -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ cosine_window ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Tensor cosine_window(int64_t window_length, - c10::optional dtype, - c10::optional layout, - c10::optional device, - c10::optional pin_memory) { - return native::cosine_window( - window_length, /*periodic=*/true, dtype, layout, device, pin_memory); -} - -Tensor cosine_window( - int64_t window_length, - bool periodic, - c10::optional dtype_opt, - c10::optional layout, - c10::optional device, - c10::optional pin_memory) { - // See [Note: hacky wrapper removal for TensorOptions] - ScalarType dtype = c10::dtype_or_default(dtype_opt); - TensorOptions options = TensorOptions().dtype(dtype).layout(layout).device(device).pinned_memory(pin_memory); - - window_function_checks("cosine_window", options, window_length); - if (window_length == 0) { - return at::empty({0}, options); - } - if (window_length == 1) { - return native::ones({1}, dtype, layout, device, pin_memory); - } - if (periodic) { - window_length += 1; - } - auto window = native::arange(window_length, dtype, layout, device, pin_memory) - .add(0.5).mul_(c10::pi).mul_(static_cast(1.0 / window_length)).sin_(); - return periodic ? window.narrow(0, 0, window_length - 1) : window; -} - // ~~~~~~~~~~~~~~~~~~~~~~~~~~ vandermonde_matrix ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index 9a6a205b50946..bf4206645946c 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -2567,16 +2567,6 @@ CUDA: grid_sampler_3d_backward_cuda autogen: grid_sampler_3d_backward.out -- func: cosine_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor - dispatch: - CompositeExplicitAutograd: cosine_window - autogen: cosine_window.out - -- func: cosine_window.periodic(int window_length, bool periodic, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor - dispatch: - CompositeExplicitAutograd: cosine_window - autogen: cosine_window.periodic_out - - func: hann_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor dispatch: CompositeExplicitAutograd: hann_window From 949cab09038a5f0e0e118c27cda5bbeeb4891d8a Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:55 -0300 Subject: [PATCH 08/76] Update docs --- docs/source/index.rst | 1 + docs/source/signal.windows.rst | 4 ++-- docs/source/torch.rst | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index cd65126d393e9..287d1f5fbaaff 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -79,6 +79,7 @@ Features described in this documentation are classified by release status: torch.linalg torch.monitor torch.special + torch.signal.windows torch.overrides torch.package profiler diff --git a/docs/source/signal.windows.rst b/docs/source/signal.windows.rst index 7261534da739f..c35b1c4c816be 100644 --- a/docs/source/signal.windows.rst +++ b/docs/source/signal.windows.rst @@ -2,9 +2,9 @@ :class: hidden-section torch.signal.windows -============= +===================== -The torch.signal.windows module, modeled after SciPy's `special `_ module. +The torch.signal.windows module, modeled after SciPy's `signal.windows `_ module. .. automodule:: torch.signal.windows .. currentmodule:: torch.signal.windows diff --git a/docs/source/torch.rst b/docs/source/torch.rst index 02b9705ee37e3..0f7a3397e5b28 100644 --- a/docs/source/torch.rst +++ b/docs/source/torch.rst @@ -475,7 +475,6 @@ Spectral Ops hamming_window hann_window kaiser_window - cosine_window Other Operations From b0c49eca3cad9611e5f231e7c5a40002115a62cd Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:55 -0300 Subject: [PATCH 09/76] Update docstrings --- torch/signal/windows/windows.py | 153 ++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 46 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 832aa4fd4cd45..3478e517b156d 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -4,7 +4,6 @@ from torch import Tensor from torch.types import _dtype, _device, _layout -from torch.fft import fft __all__ = [ 'cosine_window', @@ -13,7 +12,16 @@ ] -def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout): +def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout) -> None: + r"""Performs common checks for all the defined windows. + This function should be called before computing any window + + Args: + function_name (str): name of the window function. + window_length (int): length of the window. + dtype (:class:`torch.dtype`): the desired data type of the window tensor. + layout (:class:`torch.layout`): the desired layout of the window tensor. + """ def is_floating_type(t: _dtype) -> bool: return t == torch.float32 or t == torch.bfloat16 or t == torch.float64 or t == torch.float16 @@ -36,35 +44,52 @@ def exponential_window(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - """r - Computes a window with an exponential form. The window - is also known as Poisson window. + r"""Computes a window with an exponential form. + The window is also known as Poisson window. The exponential window is defined as follows: .. math:: - w(n) = \exp{-\frac{|n - center|}{\tau}} + w(n) = e^{-\frac{|n - center|}{\tau}} Args: - window_length: the length of the output window. In other words, the number of points of the cosine window. - periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, - returns a symmetric window suitable for use in filter design. - center: this value defines where the center of the window will be located. In other words, at which - sample the peak of the window can be found. - tau: the decay value. For `center = 0`, it's suggested to use `tau = -(M - 1) / ln(x)`, if `` is - the fraction of the window remaining at the end. + window_length (int): the length of the output window. In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`,returns a symmetric window suitable for use in filter design. + center (float, optional): this value defines where the center of the window will be located. + In other words, at which sample the peak of the window can be found. + tau (float, optional): the decay value. For `center = 0`, it's suggested to use `tau = -(M - 1) / ln(x)`, + if `x` is the fraction of the window remaining at the end. Keyword args: - {dtype} - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only - `torch.strided` (dense layout) is supported. - {device} - {requires_grad} + dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. + Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. + Only `torch.strided` (dense layout) is supported. + device (:class:`torch.device`, optional): the desired device of returned tensor. + Default: if ``None``, uses the current device for the default tensor type + (see :func:`torch.set_default_tensor_type`). + :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. + requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. + + Returns: + (torch.Tensor): window in the form of a tensor. + + Examples: + >>> # Generate an exponential window without keyword args. + >>> torch.signal.windows.exponential_window(10) + tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, + 0.0183]) + + >>> # Generate a symmetric exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential_window(10, tau=.5, periodic=False) + tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, + 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) """ if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('exponential_window', window_length, dtype, layout, device) + _window_function_checks('exponential_window', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -93,34 +118,51 @@ def cosine_window(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - """r - Computes a window with a simple cosine waveform. + r"""Computes a window with a simple cosine waveform. The cosine window is also known as the sine window due to the following equality: .. math:: - w(n) = \cos{(\frac{\pi n}{M}) - \frac{\pi}{2})} = \sin{(\frac{\pi n}{M})} + w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} Where `M` is the window length. - Args: - window_length: the length of the output window. In other words, the number of points of the cosine window. - periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, - returns a symmetric window suitable for use in filter design. + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Keyword args: - {dtype} - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only - `torch.strided` (dense layout) is supported. - {device} - {requires_grad} + dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. + Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. + Only `torch.strided` (dense layout) is supported. + device (:class:`torch.device`, optional): the desired device of returned tensor. + Default: if ``None``, uses the current device for the default tensor type + (see :func:`torch.set_default_tensor_type`). + :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. + requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. + + Returns: + (torch.Tensor): window in the form of a tensor. + + Examples: + >>> # Generate a cosine window without keyword args. + >>> torch.signal.windows.cosine_window(10) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) + + >>> # Generate a symmetric cosine window. + >>> torch.signal.windows.cosine_window(10, periodic=False) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) """ if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('cosine_window', window_length, dtype, layout, device) + _window_function_checks('cosine_window', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -133,6 +175,7 @@ def cosine_window(window_length: int, k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) window = torch.sin(torch.pi / window_length * (k + .5)) + return window[:-1] if periodic else window @@ -143,32 +186,49 @@ def gaussian_window(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - """r - Computes a window with a gaussian waveform. + r"""Computes a window with a gaussian waveform. The gaussian window is defined as follows: .. math:: - w(n) = \exp{-\frac{1}{2}\frac{n}{\sigma}^2} + w(n) = w(n) = e^{-\left(\frac{n}{2\sigma}\right)^2} Args: - window_length: the length of the output window. In other words, the number of points of the cosine window. - periodic: If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, - returns a symmetric window suitable for use in filter design. - std: the standard deviation of the gaussian. It controls how narrow or wide the window is. - + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. Keyword args: - {dtype} - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. Only - `torch.strided` (dense layout) is supported. - {device} - {requires_grad} + dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. + Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). + layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. + Only `torch.strided` (dense layout) is supported. + device (:class:`torch.device`, optional): the desired device of returned tensor. + Default: if ``None``, uses the current device for the default tensor type + (see :func:`torch.set_default_tensor_type`). + :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. + requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. + + Returns: + (torch.Tensor): window in the form of a tensor. + + Examples: + >>> # Generate a gaussian window without keyword args. + >>> torch.signal.windows.gaussian_window(10) + tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian_window(10, std=0.9, periodic=False) + tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, + 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) """ if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('cosine_window', window_length, dtype, layout, device) + _window_function_checks('cosine_window', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -183,4 +243,5 @@ def gaussian_window(window_length: int, k = k - (window_length - 1.0) / 2.0 sig2 = 2 * std * std window = torch.exp(-k ** 2 / sig2) + return window[:-1] if periodic else window From e0864e722244c4cba415708c255c244b10311301 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:56 -0300 Subject: [PATCH 10/76] Undo C++ impl --- aten/src/ATen/native/TensorFactories.cpp | 1 - aten/src/ATen/native/UnaryOps.h | 1 - aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 12 ------------ aten/src/ATen/native/native_functions.yaml | 15 --------------- 4 files changed, 29 deletions(-) diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index 3aa475a5035a5..15d765ae77b4b 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -1595,7 +1595,6 @@ Tensor rand( DEFINE_DISPATCH(kaiser_window_stub); -DEFINE_DISPATCH(chebyshev_window_stub); } // namespace native diff --git a/aten/src/ATen/native/UnaryOps.h b/aten/src/ATen/native/UnaryOps.h index 13f2bc9bbfab6..103e522fa35db 100644 --- a/aten/src/ATen/native/UnaryOps.h +++ b/aten/src/ATen/native/UnaryOps.h @@ -97,7 +97,6 @@ DECLARE_DISPATCH(void(*)(TensorIteratorBase&, c10::optional), random_ DECLARE_DISPATCH(void(*)(TensorIteratorBase&, c10::optional), random_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t, const double), kaiser_window_stub); -DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t, const double), chebyshev_window_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const int64_t), polygamma_stub); DECLARE_DISPATCH(void(*)(TensorIteratorBase&, const Scalar& a, const Scalar& b), clamp_stub); DECLARE_DISPATCH( diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index 45686dee4f123..d1830802e3a3b 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -466,17 +466,6 @@ static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length }); } -static void chebyshev_window_kernel(TensorIteratorBase& iter, int64_t window_length, double attenuation) { - AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "chebyshev_window_cpu", [&](){ - const int64_t n = window_length - 1; - const scalar_t beta = static_cast(std::cosh(1.0 / n * std::acosh(std::pow(10, attenuation / 20.0)))); - cpu_kernel(iter, [=](scalar_t a){ - auto x = beta * static_cast(std::cos(c10::pi * a / window_length)); - return static_cast(chebyshev_polynomial_t_forward(x, n) / std::pow(10, attenuation / 20.0)); - }); - }); -} - void rsqrt_kernel(TensorIteratorBase& iter) { AT_DISPATCH_FLOATING_AND_COMPLEX_TYPES_AND1(kBFloat16, iter.common_dtype(), "rsqrt_cpu", [&] { cpu_kernel_vec( @@ -746,7 +735,6 @@ REGISTER_DISPATCH(digamma_stub, &CPU_CAPABILITY::digamma_kernel); REGISTER_DISPATCH(trigamma_stub, &CPU_CAPABILITY::trigamma_kernel); REGISTER_DISPATCH(polygamma_stub, &CPU_CAPABILITY::polygamma_kernel); REGISTER_DISPATCH(kaiser_window_stub, &CPU_CAPABILITY::kaiser_window_kernel); -REGISTER_DISPATCH(chebyshev_window_stub, &CPU_CAPABILITY::chebyshev_window_kernel); REGISTER_DISPATCH(special_entr_stub, &CPU_CAPABILITY::entr_kernel); REGISTER_DISPATCH(frexp_stub, &CPU_CAPABILITY::frexp_kernel); REGISTER_DISPATCH(special_i0e_stub, &CPU_CAPABILITY::i0e_kernel); diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index bf4206645946c..3452e5f6a3088 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -2612,21 +2612,6 @@ CompositeExplicitAutograd: kaiser_window autogen: kaiser_window.beta_out -- func: chebyshev_window(int window_length, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor - dispatch: - CompositeExplicitAutograd: chebyshev_window - autogen: chebyshev_window.out - -- func: chebyshev_window.periodic(int window_length, bool periodic, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor - dispatch: - CompositeExplicitAutograd: chebyshev_window - autogen: chebyshev_window.periodic_out - -- func: chebyshev_window.periodic_attenuation(int window_length, bool periodic, float attenuation, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor - dispatch: - CompositeExplicitAutograd: chebyshev_window - autogen: chebyshev_window.periodic_attenuation_out - - func: hinge_embedding_loss(Tensor self, Tensor target, float margin=1.0, int reduction=Mean) -> Tensor - func: group_norm(Tensor input, int num_groups, Tensor? weight=None, Tensor? bias=None, float eps=1e-05, bool cudnn_enabled=True) -> Tensor From 4798e85c0ee3019722a0fd787fdf349debb79750 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:56 -0300 Subject: [PATCH 11/76] Undo old changes --- aten/src/ATen/native/SpectralOps.h | 19 ------------------- aten/src/ATen/native/TensorFactories.cpp | 1 - aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 2 +- docs/source/jit_unsupported.rst | 1 - 4 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 aten/src/ATen/native/SpectralOps.h diff --git a/aten/src/ATen/native/SpectralOps.h b/aten/src/ATen/native/SpectralOps.h deleted file mode 100644 index aa73327100d19..0000000000000 --- a/aten/src/ATen/native/SpectralOps.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace at { namespace native { - -Tensor fft_ifft(const Tensor& self, c10::optional n, int64_t dim, - c10::optional norm); - -Tensor& fft_ifft_out(const Tensor& self, c10::optional n, - int64_t dim, c10::optional norm, - Tensor& out); - -Tensor fft_fft(const Tensor& self, c10::optional n, int64_t dim, - c10::optional norm); - -}} // at::native diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index 15d765ae77b4b..ebebfa72438f8 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -1596,6 +1596,5 @@ Tensor rand( DEFINE_DISPATCH(kaiser_window_stub); - } // namespace native } // namespace at diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index d1830802e3a3b..8a0534fd3da5f 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -457,7 +457,7 @@ static void nan_to_num_kernel( }); } -static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length, double beta) { +static void kaiser_window_kernel(TensorIteratorBase& iter, int64_t window_length, double beta){ AT_DISPATCH_FLOATING_TYPES_AND(kBFloat16, iter.dtype(), "kaiser_window_cpu", [&](){ const scalar_t alpha = static_cast((window_length - 1) / 2.0); cpu_kernel(iter, [=](scalar_t a){ diff --git a/docs/source/jit_unsupported.rst b/docs/source/jit_unsupported.rst index a143825260533..7368abad1e300 100644 --- a/docs/source/jit_unsupported.rst +++ b/docs/source/jit_unsupported.rst @@ -50,7 +50,6 @@ argument, except for `torch.tensor`. This covers the following ops: * :func:`torch.eye` * :func:`torch.full` * :func:`torch.full_like` - * :func:`torch.cosine_window` * :func:`torch.hamming_window` * :func:`torch.hann_window` * :func:`torch.linspace` From 02b0fa5b88eed19c99d15654e0d071817d3999a1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:57 -0300 Subject: [PATCH 12/76] Undo old changes --- aten/src/ATen/native/SpectralOps.cpp | 2 +- aten/src/ATen/native/TensorFactories.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/aten/src/ATen/native/SpectralOps.cpp b/aten/src/ATen/native/SpectralOps.cpp index e9b8d24890678..c2e5bda454ea4 100644 --- a/aten/src/ATen/native/SpectralOps.cpp +++ b/aten/src/ATen/native/SpectralOps.cpp @@ -1223,7 +1223,7 @@ void _fft_fill_with_conjugate_symmetry_(const Tensor& input, IntArrayRef dim_) { fft_fill_with_conjugate_symmetry_stub( input.device().type(), input.scalar_type(), mirror_dims, signal_half_sizes, in_strides, in_data, out_strides, out_data); -} // namespace +} DEFINE_DISPATCH(fft_fill_with_conjugate_symmetry_stub); diff --git a/aten/src/ATen/native/TensorFactories.cpp b/aten/src/ATen/native/TensorFactories.cpp index ebebfa72438f8..2e01f7e8699ad 100644 --- a/aten/src/ATen/native/TensorFactories.cpp +++ b/aten/src/ATen/native/TensorFactories.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include From ca8450dcd00e716a49056b7cbb822e7796fda8bd Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:57 -0300 Subject: [PATCH 13/76] Add try-except --- test/test_tensor_creation_ops.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index fe3a76f26c055..bb32379a2f900 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2634,7 +2634,12 @@ def test_tensor_ctor_device_inference(self, device): def _test_signal_window_functions(self, name, dtype, device, **kwargs): import scipy.signal as signal - torch_method = getattr(torch.signal.windows, name + '_window') + try: + torch_method = getattr(torch.signal.windows, name + '_window') + except AttributeError: + # TODO: Remove try-except when all windows are moved to torch.signal.windows + torch_method = getattr(torch, name + '_window') + if not dtype.is_floating_point: with self.assertRaisesRegex(RuntimeError, r'floating point'): torch_method(3, dtype=dtype) From ef1f952d17caf321ced6e332352c37396455ff0c Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:58 -0300 Subject: [PATCH 14/76] Remove dummy code --- test/test_tensor_creation_ops.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index bb32379a2f900..aaa26a929cd61 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2700,27 +2700,6 @@ def test_gaussian_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('gaussian', dtype, device, std=random.random() * 30) - @onlyNativeDeviceTypes - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @unittest.skipIf(not TEST_SCIPY, "Scipy not found") - @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) - @dtypes(torch.float, torch.double) - def test_dummy(self, device, dtype): - from scipy import signal - - NP2TORCH = { - torch.float64: np.float64, - torch.float32: np.float32 - } - - at = 41 - window_length = 100 - w1 = signal.get_window(('chebwin', at), window_length, fftbins=False).astype(NP2TORCH[dtype]) - # w1 = signal.windows.chebwin(100, 100, sym=True).astype(NP2TORCH[dtype]) - w2 = torch.signal.windows.chebyshev_window(window_length, at=at, periodic=False, dtype=dtype, device=device) - - self.assertEqual(w1, w2, exact_dtype=True) - def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function shapes = [(5, 0, 1), (0,), (0, 0, 1, 0, 2, 0, 0)] From a02f669d4f3a8203e2f6d67e7df075dd1134e5af Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:58 -0300 Subject: [PATCH 15/76] Remove unusued import --- torch/signal/windows/windows.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 3478e517b156d..cc2e7e145ea1e 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,7 +1,5 @@ import torch -import numpy as np - from torch import Tensor from torch.types import _dtype, _device, _layout From caa6a32872773834afbf88b7ee34a975f507caa9 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:58 -0300 Subject: [PATCH 16/76] Add center --- test/test_tensor_creation_ops.py | 140 +++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 43 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index aaa26a929cd61..c4091ae07fae7 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -27,6 +27,7 @@ from torch.utils.dlpack import to_dlpack + # TODO: replace with make_tensor def _generate_input(shape, dtype, device, with_extremal): if shape == (): @@ -65,6 +66,7 @@ def _rand_shape(dim, min_size, max_size): shape.append(random.randint(min_size, max_size)) return tuple(shape) + # Test suite for tensor creation ops # # Includes creation functions like torch.eye, random creation functions like @@ -330,24 +332,24 @@ def block_diag_workaround(*arrs): self.assertEqual(result, result_check) with self.assertRaisesRegex( - RuntimeError, - "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 1 has 3 dimensions" + RuntimeError, + "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 1 has 3 dimensions" ): torch.block_diag(torch.tensor(5), torch.tensor([[[6]]])) with self.assertRaisesRegex( - RuntimeError, - "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 0 has 4 dimensions" + RuntimeError, + "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 0 has 4 dimensions" ): torch.block_diag(torch.tensor([[[[6]]]])) if device != 'cpu': with self.assertRaisesRegex( - RuntimeError, - ( - "torch.block_diag: input tensors must all be on the same device." - " Input 0 is on device cpu and input 1 is on device " - ) + RuntimeError, + ( + "torch.block_diag: input tensors must all be on the same device." + " Input 0 is on device cpu and input 1 is on device " + ) ): torch.block_diag(torch.ones(2, 2).cpu(), torch.ones(2, 2, device=device)) @@ -390,7 +392,8 @@ def test_block_diag_scipy(self, device): torch.float64 ] - for scipy_tensors, torch_type, scipy_type in zip(scipy_tensors_list, expected_torch_types, expected_scipy_types): + for scipy_tensors, torch_type, scipy_type in zip(scipy_tensors_list, expected_torch_types, + expected_scipy_types): torch_tensors = [torch.tensor(t, device=device) for t in scipy_tensors] torch_result = torch.block_diag(*torch_tensors) self.assertEqual(torch_result.dtype, torch_type) @@ -472,7 +475,7 @@ def complex_dtype_name(dtype): expected_dtype = torch.complex64 if dtype == torch.float32 else torch.complex128 error = "Expected object of scalar type {} but got scalar type " \ "{} for argument 'out'".format( - complex_dtype_name(expected_dtype), dtype_name(dtype)) + complex_dtype_name(expected_dtype), dtype_name(dtype)) with self.assertRaisesRegex(RuntimeError, error): op(a, b, out=out) @@ -575,7 +578,8 @@ def test_cat_preserve_channels_last(self, device): x = torch.randn((4, 3, 8, 8), device=device) y = torch.randn(x.shape, device=device) res1 = torch.cat((x, y)) - res2 = torch.cat((x.contiguous(memory_format=torch.channels_last), y.contiguous(memory_format=torch.channels_last))) + res2 = torch.cat( + (x.contiguous(memory_format=torch.channels_last), y.contiguous(memory_format=torch.channels_last))) self.assertEqual(res1, res2) self.assertTrue(res2.is_contiguous(memory_format=torch.channels_last)) # discontiguous channels-last inputs @@ -839,7 +843,8 @@ def _test_special_stacks(self, dim, at_least_dim, torch_fn, np_fn, device, dtype # Unless the number of dimensions is less than the corresponding at_least function dimension # Since the original concatenating dimension would shift after applying at_least and would no # longer be the concatenating dimension - if (ndims < at_least_dim or tdim != dim) and torch_input[k].size()[tdim] != torch_input[k + 1].size()[tdim]: + if (ndims < at_least_dim or tdim != dim) and torch_input[k].size()[tdim] != \ + torch_input[k + 1].size()[tdim]: valid_dim = False # Special case for hstack is needed since hstack works differently when ndims is 1 @@ -1366,7 +1371,6 @@ def test_meshgrid_vs_numpy(self, device): numpy_grids = np.meshgrid(*(tensor.cpu().numpy() for tensor in tensors), **numpy_kwargs) self.assertEqual(torch_grids, numpy_grids) - def test_cartesian_prod(self, device): a = torch.tensor([1], device=device) b = torch.tensor([1, 2, 3], device=device) @@ -1540,7 +1544,8 @@ def test_random_from_to_bool(self, device): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( + to_), lambda: t.random_(from_, to_) ) @@ -1553,13 +1558,13 @@ def test_random_full_range(self, device, dtype): int64_max_val = torch.iinfo(torch.int64).max if dtype == torch.double: - fp_limit = 2**53 + fp_limit = 2 ** 53 elif dtype == torch.float: - fp_limit = 2**24 + fp_limit = 2 ** 24 elif dtype == torch.half: - fp_limit = 2**11 + fp_limit = 2 ** 11 elif dtype == torch.bfloat16: - fp_limit = 2**8 + fp_limit = 2 ** 8 else: fp_limit = 0 @@ -1613,13 +1618,13 @@ def test_random_from_to(self, device, dtype): tos = [min_val - 1, min_val, -42, 0, 42, max_val, max_val + 1, int64_max_val] if dtype == torch.double: - fp_limit = 2**53 + fp_limit = 2 ** 53 elif dtype == torch.float: - fp_limit = 2**24 + fp_limit = 2 ** 24 elif dtype == torch.half: - fp_limit = 2**11 + fp_limit = 2 ** 11 elif dtype == torch.bfloat16: - fp_limit = 2**8 + fp_limit = 2 ** 8 else: fp_limit = 0 @@ -1663,7 +1668,8 @@ def test_random_from_to(self, device, dtype): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( + to_), lambda: t.random_(from_, to_) ) @@ -1806,7 +1812,7 @@ def test_tensor_device(self, devices): str(torch.tensor(5, dtype=torch.int64, device='cuda:1').device)) self.assertEqual('cuda:1', str(torch.tensor(torch.ones((2, 3), dtype=torch.float32), - device='cuda:1').device)) + device='cuda:1').device)) self.assertEqual('cuda:1', str(torch.tensor(np.random.randn(2, 3), device='cuda:1').device)) @@ -2038,7 +2044,8 @@ def test_tensor_factory(self, device): float64_min = torch.finfo(torch.float64).min g_1 = torch.tensor((float('nan'), 0, int64_min, int64_max, int64_min - 1), dtype=torch.bool) self.assertEqual(e, g_1) - g_2 = torch.tensor((int64_max + 1, 0, (int64_max + 1) * 2, (int64_max + 1) * 2 + 1, float64_min), dtype=torch.bool) + g_2 = torch.tensor((int64_max + 1, 0, (int64_max + 1) * 2, (int64_max + 1) * 2 + 1, float64_min), + dtype=torch.bool) self.assertEqual(e, g_2) g_3 = torch.tensor((float64_max, 0, float64_max + 1, float64_min - 1, float64_max + 1e291), dtype=torch.bool) self.assertEqual(e, g_3) @@ -2471,7 +2478,7 @@ def _test(sizes, strides, dtype): x.new_empty_strided(size, stride, dtype=dtype, device=device) def test_strided_mismatched_stride_shape(self, device): - for shape, strides in [((1, ), ()), ((1, 2), (1, ))]: + for shape, strides in [((1,), ()), ((1, 2), (1,))]: with self.assertRaisesRegex(RuntimeError, "mismatch in length of strides and shape"): torch.tensor(0.42, device=device).as_strided(shape, strides) @@ -2491,11 +2498,11 @@ def test_empty_tensor_props(self, device): @onlyNativeDeviceTypes def test_empty_overflow(self, device): with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty([2, 4, 2**29, 2**29], dtype=torch.float64) + torch.empty([2, 4, 2 ** 29, 2 ** 29], dtype=torch.float64) with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty([8, 8, 2**29, 2**29], dtype=torch.float64) + torch.empty([8, 8, 2 ** 29, 2 ** 29], dtype=torch.float64) with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty_strided([8, 8], [2**61, 1], dtype=torch.float64) + torch.empty_strided([8, 8], [2 ** 61, 1], dtype=torch.float64) def test_eye(self, device): for dtype in all_types_and_complex_and(torch.half, torch.bool, torch.bfloat16): @@ -2536,7 +2543,7 @@ def test_linspace_vs_numpy(self, device, dtype): start = -0.0316082797944545745849609375 + (0.8888888888j if dtype.is_complex else 0) end = .0315315723419189453125 + (0.444444444444j if dtype.is_complex else 0) - for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: t = torch.linspace(start, end, steps, device=device, dtype=dtype) a = np.linspace(start, end, steps, dtype=torch_to_numpy_dtype_dict[dtype]) t = t.cpu() @@ -2554,7 +2561,7 @@ def test_fn(torch_fn, numpy_fn, steps): t = t.cpu() self.assertEqual(t, torch.from_numpy(a)) - for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: test_fn(torch.linspace, np.linspace, steps) @dtypes(torch.complex64) @@ -2573,7 +2580,7 @@ def test_logspace_vs_numpy(self, device, dtype): start = -0.0316082797944545745849609375 end = .0315315723419189453125 - for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: t = torch.logspace(start, end, steps, device=device, dtype=dtype) a = np.logspace(start, end, steps, dtype=torch_to_numpy_dtype_dict[dtype]) t = t.cpu() @@ -2646,6 +2653,10 @@ def _test_signal_window_functions(self, name, dtype, device, **kwargs): return for size in [0, 1, 2, 5, 10, 50, 100, 1024, 2048]: for periodic in [True, False]: + print(*(kwargs.values())) + print(size) + print(periodic) + res = torch_method(size, periodic=periodic, **kwargs, device=device, dtype=dtype) # NB: scipy always returns a float64 result ref = torch.from_numpy(signal.get_window((name, *(kwargs.values())), size, fftbins=periodic)) @@ -2689,7 +2700,13 @@ def test_cosine_window(self, device, dtype): @dtypes(torch.float, torch.double, torch.long) def test_exponential_window(self, device, dtype): for num_test in range(50): - self._test_signal_window_functions('exponential', dtype, device) + self._test_signal_window_functions( + 'exponential', + dtype, + device, + center=None, + tau=round(random.uniform(0, 2), 2), + ) @onlyNativeDeviceTypes @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) @@ -2700,6 +2717,27 @@ def test_gaussian_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('gaussian', dtype, device, std=random.random() * 30) + # @onlyNativeDeviceTypes + # @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + # @unittest.skipIf(not TEST_SCIPY, "Scipy not found") + # @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) + # @dtypes(torch.float, torch.double) + # def test_dummy(self, device, dtype): + # from scipy import signal + # + # NP2TORCH = { + # torch.float64: np.float64, + # torch.float32: np.float32 + # } + # + # at = 41 + # window_length = 100 + # w1 = signal.get_window(('chebwin', at), window_length, fftbins=False).astype(NP2TORCH[dtype]) + # # w1 = signal.windows.chebwin(100, 100, sym=True).astype(NP2TORCH[dtype]) + # w2 = torch.signal.windows.chebyshev_window(window_length, at=at, periodic=False, dtype=dtype, device=device) + # + # self.assertEqual(w1, w2, exact_dtype=True) + def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function shapes = [(5, 0, 1), (0,), (0, 0, 1, 0, 2, 0, 0)] @@ -2958,7 +2996,7 @@ def test_logspace_special_steps(self, device, dtype): @dtypes(*all_types_and(torch.bfloat16)) @dtypesIfCUDA(*integral_types_and(torch.half, torch.bfloat16, torch.float32, torch.float64) if TEST_WITH_ROCM else - all_types_and(torch.half, torch.bfloat16)) + all_types_and(torch.half, torch.bfloat16)) def test_logspace(self, device, dtype): _from = random.random() to = _from + random.random() @@ -3397,11 +3435,11 @@ def test_randperm(self, device): self.assertEqual(res2.numel(), 0) # Test exceptions when n is too large for a floating point type - for dtype, small_n, large_n in ((torch.uint8, 2**8, 2**8 + 1), - (torch.half, 2**11 + 1, 2**11 + 2), - (torch.float, 2**24 + 1, 2**24 + 2), - (torch.double, 2**25, # 2**53 + 1 is too large to run - 2**53 + 2)): + for dtype, small_n, large_n in ((torch.uint8, 2 ** 8, 2 ** 8 + 1), + (torch.half, 2 ** 11 + 1, 2 ** 11 + 2), + (torch.float, 2 ** 24 + 1, 2 ** 24 + 2), + (torch.double, 2 ** 25, # 2**53 + 1 is too large to run + 2 ** 53 + 2)): res = torch.empty(0, dtype=dtype, device=device) torch.randperm(small_n, out=res) # No exception expected self.assertRaises(RuntimeError, lambda: torch.randperm(large_n, out=res, device=device)) @@ -3445,11 +3483,15 @@ def test_randperm_device_compatibility(self, device): regex = 'Expected a .* device type for generator but found .*' cuda_t = torch.tensor(n, device='cuda') self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cuda', generator=cpu_gen)) - self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cuda', generator=cpu_gen, out=cuda_t)) + self.assertRaisesRegex(RuntimeError, regex, + lambda: torch.randperm(n, device='cuda', generator=cpu_gen, out=cuda_t)) cpu_t = torch.tensor(n, device='cpu') self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cpu', generator=cuda_gen)) - self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cpu', generator=cuda_gen, out=cpu_t)) - self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, generator=cuda_gen)) # implicitly on CPU + self.assertRaisesRegex(RuntimeError, regex, + lambda: torch.randperm(n, device='cpu', generator=cuda_gen, out=cpu_t)) + self.assertRaisesRegex(RuntimeError, regex, + lambda: torch.randperm(n, generator=cuda_gen)) # implicitly on CPU + # Class for testing *like ops, like torch.ones_like class TestLikeTensorCreation(TestCase): @@ -3508,18 +3550,22 @@ def test_full_like_inference(self, device): self.assertEqual(torch.full_like(like, 1., dtype=torch.complex64).dtype, torch.complex64) + # Tests for the `frombuffer` function (only work on CPU): # Constructs tensors from Python objects that implement the buffer protocol, # without copying data. SIZE = 5 SHAPE = (SIZE,) + def may_require_grad(dtype): return dtype.is_floating_point or dtype.is_complex + def get_dtype_size(dtype): return int(torch.empty((), dtype=dtype).element_size()) + class TestBufferProtocol(TestCase): def _run_test(self, shape, dtype, count=-1, first=0, offset=None, **kwargs): numpy_dtype = torch_to_numpy_dtype_dict[dtype] @@ -3675,6 +3721,7 @@ def test_byte_to_int(self): # Assuming little endian machine self.assertSequenceEqual(tensor, [255, 255]) + # Tests for the `asarray` function: # Constructs tensors from a Python object that has one of the following # characteristics: @@ -3687,13 +3734,19 @@ def test_byte_to_int(self): def get_another_device(device): return "cuda" if torch.device(device).type == "cpu" else "cpu" + def identity(tensor): return tensor + + def to_numpy(tensor): return tensor.numpy() + + def to_memview(tensor): return memoryview(to_numpy(tensor)) + class TestAsArray(TestCase): def _check(self, original, cvt=lambda t: t, is_alias=True, same_dtype=True, same_device=True, **kwargs): """Check the output of 'asarray', given its input and assertion informations. @@ -3942,6 +3995,7 @@ def test_astensor_consistency(self, device): t = torch.asarray(e) self.assertEqual(t, original) + instantiate_device_type_tests(TestTensorCreation, globals()) instantiate_device_type_tests(TestRandomTensorCreation, globals()) instantiate_device_type_tests(TestLikeTensorCreation, globals()) From c44c4c05b96c920ab8a9b5354e0e3ba3b5ec8f8e Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:59 -0300 Subject: [PATCH 17/76] fix lin issues --- test/test_tensor_creation_ops.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index c4091ae07fae7..00223695b68d3 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -345,11 +345,11 @@ def block_diag_workaround(*arrs): if device != 'cpu': with self.assertRaisesRegex( - RuntimeError, - ( - "torch.block_diag: input tensors must all be on the same device." - " Input 0 is on device cpu and input 1 is on device " - ) + RuntimeError, + ( + "torch.block_diag: input tensors must all be on the same device." + " Input 0 is on device cpu and input 1 is on device " + ) ): torch.block_diag(torch.ones(2, 2).cpu(), torch.ones(2, 2, device=device)) @@ -474,8 +474,7 @@ def complex_dtype_name(dtype): out = torch.zeros(2, device=device, dtype=dtype) expected_dtype = torch.complex64 if dtype == torch.float32 else torch.complex128 error = "Expected object of scalar type {} but got scalar type " \ - "{} for argument 'out'".format( - complex_dtype_name(expected_dtype), dtype_name(dtype)) + "{} for argument 'out'".format(complex_dtype_name(expected_dtype), dtype_name(dtype)) with self.assertRaisesRegex(RuntimeError, error): op(a, b, out=out) @@ -2995,8 +2994,10 @@ def test_logspace_special_steps(self, device, dtype): self._test_logspace_base2(device, dtype, steps=steps) @dtypes(*all_types_and(torch.bfloat16)) - @dtypesIfCUDA(*integral_types_and(torch.half, torch.bfloat16, torch.float32, torch.float64) if TEST_WITH_ROCM else - all_types_and(torch.half, torch.bfloat16)) + @dtypesIfCUDA( + *integral_types_and(torch.half, torch.bfloat16, torch.float32, torch.float64) if TEST_WITH_ROCM else + all_types_and(torch.half, torch.bfloat16) + ) def test_logspace(self, device, dtype): _from = random.random() to = _from + random.random() From de61473856cc38baf3dcb1a81541ad451f36b28e Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:13:59 -0300 Subject: [PATCH 18/76] remove unused code --- test/test_tensor_creation_ops.py | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 00223695b68d3..1dfe8f0317dda 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2579,7 +2579,7 @@ def test_logspace_vs_numpy(self, device, dtype): start = -0.0316082797944545745849609375 end = .0315315723419189453125 - for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: t = torch.logspace(start, end, steps, device=device, dtype=dtype) a = np.logspace(start, end, steps, dtype=torch_to_numpy_dtype_dict[dtype]) t = t.cpu() @@ -2652,10 +2652,6 @@ def _test_signal_window_functions(self, name, dtype, device, **kwargs): return for size in [0, 1, 2, 5, 10, 50, 100, 1024, 2048]: for periodic in [True, False]: - print(*(kwargs.values())) - print(size) - print(periodic) - res = torch_method(size, periodic=periodic, **kwargs, device=device, dtype=dtype) # NB: scipy always returns a float64 result ref = torch.from_numpy(signal.get_window((name, *(kwargs.values())), size, fftbins=periodic)) @@ -2716,26 +2712,6 @@ def test_gaussian_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('gaussian', dtype, device, std=random.random() * 30) - # @onlyNativeDeviceTypes - # @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - # @unittest.skipIf(not TEST_SCIPY, "Scipy not found") - # @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) - # @dtypes(torch.float, torch.double) - # def test_dummy(self, device, dtype): - # from scipy import signal - # - # NP2TORCH = { - # torch.float64: np.float64, - # torch.float32: np.float32 - # } - # - # at = 41 - # window_length = 100 - # w1 = signal.get_window(('chebwin', at), window_length, fftbins=False).astype(NP2TORCH[dtype]) - # # w1 = signal.windows.chebwin(100, 100, sym=True).astype(NP2TORCH[dtype]) - # w2 = torch.signal.windows.chebyshev_window(window_length, at=at, periodic=False, dtype=dtype, device=device) - # - # self.assertEqual(w1, w2, exact_dtype=True) def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function From ad8850cdb13c0928f76e764d5a5752d4151d97d8 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:00 -0300 Subject: [PATCH 19/76] fixing changes --- test/test_tensor_creation_ops.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 1dfe8f0317dda..f72a1e3c3527f 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -1543,8 +1543,7 @@ def test_random_from_to_bool(self, device): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( - to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), lambda: t.random_(from_, to_) ) @@ -1810,8 +1809,7 @@ def test_tensor_device(self, devices): self.assertEqual('cuda:1', str(torch.tensor(5, dtype=torch.int64, device='cuda:1').device)) self.assertEqual('cuda:1', - str(torch.tensor(torch.ones((2, 3), dtype=torch.float32), - device='cuda:1').device)) + str(torch.tensor(torch.ones((2, 3), dtype=torch.float32), device='cuda:1').device)) self.assertEqual('cuda:1', str(torch.tensor(np.random.randn(2, 3), device='cuda:1').device)) @@ -2043,8 +2041,7 @@ def test_tensor_factory(self, device): float64_min = torch.finfo(torch.float64).min g_1 = torch.tensor((float('nan'), 0, int64_min, int64_max, int64_min - 1), dtype=torch.bool) self.assertEqual(e, g_1) - g_2 = torch.tensor((int64_max + 1, 0, (int64_max + 1) * 2, (int64_max + 1) * 2 + 1, float64_min), - dtype=torch.bool) + g_2 = torch.tensor((int64_max + 1, 0, (int64_max + 1) * 2, (int64_max + 1) * 2 + 1, float64_min), dtype=torch.bool) self.assertEqual(e, g_2) g_3 = torch.tensor((float64_max, 0, float64_max + 1, float64_min - 1, float64_max + 1e291), dtype=torch.bool) self.assertEqual(e, g_3) @@ -2497,11 +2494,11 @@ def test_empty_tensor_props(self, device): @onlyNativeDeviceTypes def test_empty_overflow(self, device): with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty([2, 4, 2 ** 29, 2 ** 29], dtype=torch.float64) + torch.empty([2, 4, 2**29, 2**29], dtype=torch.float64) with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty([8, 8, 2 ** 29, 2 ** 29], dtype=torch.float64) + torch.empty([8, 8, 2**29, 2**29], dtype=torch.float64) with self.assertRaisesRegex(RuntimeError, 'Storage size calculation overflowed'): - torch.empty_strided([8, 8], [2 ** 61, 1], dtype=torch.float64) + torch.empty_strided([8, 8], [2**61, 1], dtype=torch.float64) def test_eye(self, device): for dtype in all_types_and_complex_and(torch.half, torch.bool, torch.bfloat16): @@ -2542,7 +2539,7 @@ def test_linspace_vs_numpy(self, device, dtype): start = -0.0316082797944545745849609375 + (0.8888888888j if dtype.is_complex else 0) end = .0315315723419189453125 + (0.444444444444j if dtype.is_complex else 0) - for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: t = torch.linspace(start, end, steps, device=device, dtype=dtype) a = np.linspace(start, end, steps, dtype=torch_to_numpy_dtype_dict[dtype]) t = t.cpu() @@ -2560,7 +2557,7 @@ def test_fn(torch_fn, numpy_fn, steps): t = t.cpu() self.assertEqual(t, torch.from_numpy(a)) - for steps in [1, 2, 3, 5, 11, 256, 257, 2 ** 22]: + for steps in [1, 2, 3, 5, 11, 256, 257, 2**22]: test_fn(torch.linspace, np.linspace, steps) @dtypes(torch.complex64) From 4fd93cb4debda645ad69acf54c0145ad357dd914 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:00 -0300 Subject: [PATCH 20/76] fixing lints --- test/test_tensor_creation_ops.py | 39 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index f72a1e3c3527f..1278bb35f3511 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -332,14 +332,14 @@ def block_diag_workaround(*arrs): self.assertEqual(result, result_check) with self.assertRaisesRegex( - RuntimeError, - "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 1 has 3 dimensions" + RuntimeError, + "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 1 has 3 dimensions" ): torch.block_diag(torch.tensor(5), torch.tensor([[[6]]])) with self.assertRaisesRegex( - RuntimeError, - "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 0 has 4 dimensions" + RuntimeError, + "torch.block_diag: Input tensors must have 2 or fewer dimensions. Input 0 has 4 dimensions" ): torch.block_diag(torch.tensor([[[[6]]]])) @@ -935,7 +935,7 @@ def test_large_linspace(self, device, dtype): @dtypes(torch.float32, torch.float64) def test_unpack_double(self, device, dtype): # Reference: https://github.com/pytorch/pytorch/issues/33111 - vals = (2 ** 24 + 1, 2 ** 53 + 1, + vals = (2**24 + 1, 2**53 + 1, np.iinfo(np.int64).max, np.iinfo(np.uint64).max, np.iinfo(np.uint64).max + 1, -1e500, 1e500) for val in vals: @@ -1543,7 +1543,8 @@ def test_random_from_to_bool(self, device): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( + to_), lambda: t.random_(from_, to_) ) @@ -1556,13 +1557,13 @@ def test_random_full_range(self, device, dtype): int64_max_val = torch.iinfo(torch.int64).max if dtype == torch.double: - fp_limit = 2 ** 53 + fp_limit = 2**53 elif dtype == torch.float: - fp_limit = 2 ** 24 + fp_limit = 2**24 elif dtype == torch.half: - fp_limit = 2 ** 11 + fp_limit = 2**11 elif dtype == torch.bfloat16: - fp_limit = 2 ** 8 + fp_limit = 2**8 else: fp_limit = 0 @@ -1616,13 +1617,13 @@ def test_random_from_to(self, device, dtype): tos = [min_val - 1, min_val, -42, 0, 42, max_val, max_val + 1, int64_max_val] if dtype == torch.double: - fp_limit = 2 ** 53 + fp_limit = 2**53 elif dtype == torch.float: - fp_limit = 2 ** 24 + fp_limit = 2**24 elif dtype == torch.half: - fp_limit = 2 ** 11 + fp_limit = 2**11 elif dtype == torch.bfloat16: - fp_limit = 2 ** 8 + fp_limit = 2**8 else: fp_limit = 0 @@ -3409,11 +3410,11 @@ def test_randperm(self, device): self.assertEqual(res2.numel(), 0) # Test exceptions when n is too large for a floating point type - for dtype, small_n, large_n in ((torch.uint8, 2 ** 8, 2 ** 8 + 1), - (torch.half, 2 ** 11 + 1, 2 ** 11 + 2), - (torch.float, 2 ** 24 + 1, 2 ** 24 + 2), - (torch.double, 2 ** 25, # 2**53 + 1 is too large to run - 2 ** 53 + 2)): + for dtype, small_n, large_n in ((torch.uint8, 2**8, 2**8 + 1), + (torch.half, 2**11 + 1, 2**11 + 2), + (torch.float, 2**24 + 1, 2**24 + 2), + (torch.double, 2**25, # 2**53 + 1 is too large to run + 2**53 + 2)): res = torch.empty(0, dtype=dtype, device=device) torch.randperm(small_n, out=res) # No exception expected self.assertRaises(RuntimeError, lambda: torch.randperm(large_n, out=res, device=device)) From fa26443d807abd4ed8d52be9041f82b1438484bc Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:01 -0300 Subject: [PATCH 21/76] fixing lints --- test/test_tensor_creation_ops.py | 42 +++++++++----------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 1278bb35f3511..b3d5f1da5e432 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -66,7 +66,6 @@ def _rand_shape(dim, min_size, max_size): shape.append(random.randint(min_size, max_size)) return tuple(shape) - # Test suite for tensor creation ops # # Includes creation functions like torch.eye, random creation functions like @@ -392,8 +391,7 @@ def test_block_diag_scipy(self, device): torch.float64 ] - for scipy_tensors, torch_type, scipy_type in zip(scipy_tensors_list, expected_torch_types, - expected_scipy_types): + for scipy_tensors, torch_type, scipy_type in zip(scipy_tensors_list, expected_torch_types, expected_scipy_types): torch_tensors = [torch.tensor(t, device=device) for t in scipy_tensors] torch_result = torch.block_diag(*torch_tensors) self.assertEqual(torch_result.dtype, torch_type) @@ -935,7 +933,7 @@ def test_large_linspace(self, device, dtype): @dtypes(torch.float32, torch.float64) def test_unpack_double(self, device, dtype): # Reference: https://github.com/pytorch/pytorch/issues/33111 - vals = (2**24 + 1, 2**53 + 1, + vals = (2 ** 24 + 1, 2 ** 53 + 1, np.iinfo(np.int64).max, np.iinfo(np.uint64).max, np.iinfo(np.uint64).max + 1, -1e500, 1e500) for val in vals: @@ -1543,8 +1541,7 @@ def test_random_from_to_bool(self, device): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( - to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), lambda: t.random_(from_, to_) ) @@ -1667,8 +1664,7 @@ def test_random_from_to(self, device, dtype): else: self.assertRaisesRegex( RuntimeError, - "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str( - to_), + "random_ expects 'from' to be less than 'to', but got from=" + str(from_) + " >= to=" + str(to_), lambda: t.random_(from_, to_) ) @@ -1810,7 +1806,8 @@ def test_tensor_device(self, devices): self.assertEqual('cuda:1', str(torch.tensor(5, dtype=torch.int64, device='cuda:1').device)) self.assertEqual('cuda:1', - str(torch.tensor(torch.ones((2, 3), dtype=torch.float32), device='cuda:1').device)) + str(torch.tensor(torch.ones((2, 3), dtype=torch.float32), + device='cuda:1').device)) self.assertEqual('cuda:1', str(torch.tensor(np.random.randn(2, 3), device='cuda:1').device)) @@ -2475,7 +2472,7 @@ def _test(sizes, strides, dtype): x.new_empty_strided(size, stride, dtype=dtype, device=device) def test_strided_mismatched_stride_shape(self, device): - for shape, strides in [((1,), ()), ((1, 2), (1,))]: + for shape, strides in [((1, ), ()), ((1, 2), (1, ))]: with self.assertRaisesRegex(RuntimeError, "mismatch in length of strides and shape"): torch.tensor(0.42, device=device).as_strided(shape, strides) @@ -2968,10 +2965,8 @@ def test_logspace_special_steps(self, device, dtype): self._test_logspace_base2(device, dtype, steps=steps) @dtypes(*all_types_and(torch.bfloat16)) - @dtypesIfCUDA( - *integral_types_and(torch.half, torch.bfloat16, torch.float32, torch.float64) if TEST_WITH_ROCM else - all_types_and(torch.half, torch.bfloat16) - ) + @dtypesIfCUDA(*integral_types_and(torch.half, torch.bfloat16, torch.float32, torch.float64) if TEST_WITH_ROCM else + all_types_and(torch.half, torch.bfloat16)) def test_logspace(self, device, dtype): _from = random.random() to = _from + random.random() @@ -3458,14 +3453,11 @@ def test_randperm_device_compatibility(self, device): regex = 'Expected a .* device type for generator but found .*' cuda_t = torch.tensor(n, device='cuda') self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cuda', generator=cpu_gen)) - self.assertRaisesRegex(RuntimeError, regex, - lambda: torch.randperm(n, device='cuda', generator=cpu_gen, out=cuda_t)) + self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cuda', generator=cpu_gen, out=cuda_t)) cpu_t = torch.tensor(n, device='cpu') self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cpu', generator=cuda_gen)) - self.assertRaisesRegex(RuntimeError, regex, - lambda: torch.randperm(n, device='cpu', generator=cuda_gen, out=cpu_t)) - self.assertRaisesRegex(RuntimeError, regex, - lambda: torch.randperm(n, generator=cuda_gen)) # implicitly on CPU + self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cpu', generator=cuda_gen, out=cpu_t)) + self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, generator=cuda_gen)) # implicitly on CPU # Class for testing *like ops, like torch.ones_like @@ -3532,15 +3524,12 @@ def test_full_like_inference(self, device): SIZE = 5 SHAPE = (SIZE,) - def may_require_grad(dtype): return dtype.is_floating_point or dtype.is_complex - def get_dtype_size(dtype): return int(torch.empty((), dtype=dtype).element_size()) - class TestBufferProtocol(TestCase): def _run_test(self, shape, dtype, count=-1, first=0, offset=None, **kwargs): numpy_dtype = torch_to_numpy_dtype_dict[dtype] @@ -3709,19 +3698,13 @@ def test_byte_to_int(self): def get_another_device(device): return "cuda" if torch.device(device).type == "cpu" else "cpu" - def identity(tensor): return tensor - - def to_numpy(tensor): return tensor.numpy() - - def to_memview(tensor): return memoryview(to_numpy(tensor)) - class TestAsArray(TestCase): def _check(self, original, cvt=lambda t: t, is_alias=True, same_dtype=True, same_device=True, **kwargs): """Check the output of 'asarray', given its input and assertion informations. @@ -3970,7 +3953,6 @@ def test_astensor_consistency(self, device): t = torch.asarray(e) self.assertEqual(t, original) - instantiate_device_type_tests(TestTensorCreation, globals()) instantiate_device_type_tests(TestRandomTensorCreation, globals()) instantiate_device_type_tests(TestLikeTensorCreation, globals()) From 18910eb8237cbfed9f2627a8bbc74d8fd597ba95 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:01 -0300 Subject: [PATCH 22/76] fixing lints --- test/test_tensor_creation_ops.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index b3d5f1da5e432..4b43166e72263 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -27,7 +27,6 @@ from torch.utils.dlpack import to_dlpack - # TODO: replace with make_tensor def _generate_input(shape, dtype, device, with_extremal): if shape == (): @@ -575,8 +574,7 @@ def test_cat_preserve_channels_last(self, device): x = torch.randn((4, 3, 8, 8), device=device) y = torch.randn(x.shape, device=device) res1 = torch.cat((x, y)) - res2 = torch.cat( - (x.contiguous(memory_format=torch.channels_last), y.contiguous(memory_format=torch.channels_last))) + res2 = torch.cat((x.contiguous(memory_format=torch.channels_last), y.contiguous(memory_format=torch.channels_last))) self.assertEqual(res1, res2) self.assertTrue(res2.is_contiguous(memory_format=torch.channels_last)) # discontiguous channels-last inputs @@ -840,8 +838,7 @@ def _test_special_stacks(self, dim, at_least_dim, torch_fn, np_fn, device, dtype # Unless the number of dimensions is less than the corresponding at_least function dimension # Since the original concatenating dimension would shift after applying at_least and would no # longer be the concatenating dimension - if (ndims < at_least_dim or tdim != dim) and torch_input[k].size()[tdim] != \ - torch_input[k + 1].size()[tdim]: + if (ndims < at_least_dim or tdim != dim) and torch_input[k].size()[tdim] != torch_input[k + 1].size()[tdim]: valid_dim = False # Special case for hstack is needed since hstack works differently when ndims is 1 @@ -1368,6 +1365,7 @@ def test_meshgrid_vs_numpy(self, device): numpy_grids = np.meshgrid(*(tensor.cpu().numpy() for tensor in tensors), **numpy_kwargs) self.assertEqual(torch_grids, numpy_grids) + def test_cartesian_prod(self, device): a = torch.tensor([1], device=device) b = torch.tensor([1, 2, 3], device=device) @@ -3459,7 +3457,6 @@ def test_randperm_device_compatibility(self, device): self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, device='cpu', generator=cuda_gen, out=cpu_t)) self.assertRaisesRegex(RuntimeError, regex, lambda: torch.randperm(n, generator=cuda_gen)) # implicitly on CPU - # Class for testing *like ops, like torch.ones_like class TestLikeTensorCreation(TestCase): exact_dtype = True @@ -3517,7 +3514,6 @@ def test_full_like_inference(self, device): self.assertEqual(torch.full_like(like, 1., dtype=torch.complex64).dtype, torch.complex64) - # Tests for the `frombuffer` function (only work on CPU): # Constructs tensors from Python objects that implement the buffer protocol, # without copying data. @@ -3685,7 +3681,6 @@ def test_byte_to_int(self): # Assuming little endian machine self.assertSequenceEqual(tensor, [255, 255]) - # Tests for the `asarray` function: # Constructs tensors from a Python object that has one of the following # characteristics: From d0845af8a3824e7aee7b5dfec9eaf291a64b7117 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:02 -0300 Subject: [PATCH 23/76] fixing lints --- test/test_tensor_creation_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 4b43166e72263..3c5efd0eedadc 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -471,7 +471,8 @@ def complex_dtype_name(dtype): out = torch.zeros(2, device=device, dtype=dtype) expected_dtype = torch.complex64 if dtype == torch.float32 else torch.complex128 error = "Expected object of scalar type {} but got scalar type " \ - "{} for argument 'out'".format(complex_dtype_name(expected_dtype), dtype_name(dtype)) + "{} for argument 'out'".format( + complex_dtype_name(expected_dtype), dtype_name(dtype)) with self.assertRaisesRegex(RuntimeError, error): op(a, b, out=out) From ae8f46a9cec19cdefbb7304bacacd3fd4c2b77a1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:02 -0300 Subject: [PATCH 24/76] update docs --- docs/source/index.rst | 2 +- docs/source/signal.rst | 28 ++++++++++++++++++++++++++++ docs/source/signal.windows.rst | 17 ----------------- torch/signal/windows/windows.py | 2 +- 4 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 docs/source/signal.rst delete mode 100644 docs/source/signal.windows.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 287d1f5fbaaff..2c0390434d50c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -79,7 +79,7 @@ Features described in this documentation are classified by release status: torch.linalg torch.monitor torch.special - torch.signal.windows + torch.signal torch.overrides torch.package profiler diff --git a/docs/source/signal.rst b/docs/source/signal.rst new file mode 100644 index 0000000000000..d0fb58d70af95 --- /dev/null +++ b/docs/source/signal.rst @@ -0,0 +1,28 @@ +.. role:: hidden + :class: hidden-section + +torch.signal +============ +.. automodule:: torch.signal +.. currentmodule:: torch.signal + +The `torch.signal` module, modeled after SciPy's `signal `_ module. + +.. contents:: torch.signal + :depth: 1 + :local: + :backlinks: top + +torch.signal.windows +-------------------- + +.. automodule:: torch.signal.windows +.. currentmodule:: torch.signal.windows + +.. autosummary:: + :toctree: generated + :nosignatures: + + cosine_window + exponential_window + gaussian_window diff --git a/docs/source/signal.windows.rst b/docs/source/signal.windows.rst deleted file mode 100644 index c35b1c4c816be..0000000000000 --- a/docs/source/signal.windows.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. role:: hidden - :class: hidden-section - -torch.signal.windows -===================== - -The torch.signal.windows module, modeled after SciPy's `signal.windows `_ module. - -.. automodule:: torch.signal.windows -.. currentmodule:: torch.signal.windows - -Functions ------------------------ - -.. autofunction:: cosine_window -.. autofunction:: exponential_window -.. autofunction:: gaussian_window diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index cc2e7e145ea1e..3e242459cc497 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -189,7 +189,7 @@ def gaussian_window(window_length: int, The gaussian window is defined as follows: .. math:: - w(n) = w(n) = e^{-\left(\frac{n}{2\sigma}\right)^2} + w(n) = e^{-\left(\frac{n}{2\sigma}\right)^2} Args: window_length (int): the length of the output window. From 8666c9df5243f5c42a0806cd1776e5c89293d1b5 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:03 -0300 Subject: [PATCH 25/76] Reduce computation time and improve numeric stability --- torch/signal/windows/windows.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 3e242459cc497..cbb5daa9ebb86 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -239,7 +239,6 @@ def gaussian_window(window_length: int, k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) k = k - (window_length - 1.0) / 2.0 - sig2 = 2 * std * std - window = torch.exp(-k ** 2 / sig2) + window = torch.exp(-(k / std) ** 2 / 2) return window[:-1] if periodic else window From 19ac11970cf78b15e45c43feae60cdae85a32c30 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:03 -0300 Subject: [PATCH 26/76] Update gaussian and exp windows --- torch/signal/windows/windows.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index cbb5daa9ebb86..ba9d5984d4def 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -20,6 +20,7 @@ def _window_function_checks(function_name: str, window_length: int, dtype: _dtyp dtype (:class:`torch.dtype`): the desired data type of the window tensor. layout (:class:`torch.layout`): the desired layout of the window tensor. """ + def is_floating_type(t: _dtype) -> bool: return t == torch.float32 or t == torch.bfloat16 or t == torch.float64 or t == torch.float16 @@ -95,19 +96,19 @@ def exponential_window(window_length: int, if window_length == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if periodic: - window_length += 1 - if periodic and center is not None: raise ValueError('Center must be \'None\' for periodic equal True') if center is None: - center = (window_length - 1) / 2 + center = -(window_length if periodic else window_length - 1) / 2.0 - k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - window = torch.exp(-torch.abs(k - center) / tau) + k = torch.arange(start=center, + end=center + window_length, + dtype=dtype, layout=layout, + device=device, + requires_grad=requires_grad) - return window[:-1] if periodic else window + return torch.exp(-torch.abs(k) / tau) def cosine_window(window_length: int, @@ -234,11 +235,13 @@ def gaussian_window(window_length: int, if window_length == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if periodic: - window_length += 1 + start = -(window_length if periodic else window_length - 1) / 2.0 - k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - k = k - (window_length - 1.0) / 2.0 - window = torch.exp(-(k / std) ** 2 / 2) + k = torch.arange(start, + start + window_length, + dtype=dtype, + layout=layout, + device=device, + requires_grad=requires_grad) - return window[:-1] if periodic else window + return torch.exp(-(k / std) ** 2 / 2) From 6225f649f68506d2ba58d16d91fce0dd876c8dee Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:03 -0300 Subject: [PATCH 27/76] Address review --- docs/source/signal.rst | 11 +--- test/test_tensor_creation_ops.py | 6 +- torch/signal/__init__.py | 6 +- torch/signal/windows/__init__.py | 8 +-- torch/signal/windows/windows.py | 97 +++++++++++++++----------------- 5 files changed, 56 insertions(+), 72 deletions(-) diff --git a/docs/source/signal.rst b/docs/source/signal.rst index d0fb58d70af95..e304092ede5ed 100644 --- a/docs/source/signal.rst +++ b/docs/source/signal.rst @@ -8,11 +8,6 @@ torch.signal The `torch.signal` module, modeled after SciPy's `signal `_ module. -.. contents:: torch.signal - :depth: 1 - :local: - :backlinks: top - torch.signal.windows -------------------- @@ -23,6 +18,6 @@ torch.signal.windows :toctree: generated :nosignatures: - cosine_window - exponential_window - gaussian_window + cosine + exponential + gaussian diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 3c5efd0eedadc..d723524167dd5 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2634,11 +2634,7 @@ def test_tensor_ctor_device_inference(self, device): def _test_signal_window_functions(self, name, dtype, device, **kwargs): import scipy.signal as signal - try: - torch_method = getattr(torch.signal.windows, name + '_window') - except AttributeError: - # TODO: Remove try-except when all windows are moved to torch.signal.windows - torch_method = getattr(torch, name + '_window') + torch_method = getattr(torch.signal.windows, name) if not dtype.is_floating_point: with self.assertRaisesRegex(RuntimeError, r'floating point'): diff --git a/torch/signal/__init__.py b/torch/signal/__init__.py index f79d655133999..3684eabe71215 100644 --- a/torch/signal/__init__.py +++ b/torch/signal/__init__.py @@ -1,7 +1,5 @@ -from .windows import cosine_window, exponential_window, gaussian_window +from . import windows __all__ = [ - 'cosine_window', - 'exponential_window', - 'gaussian_window', + 'windows' ] diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index f79d655133999..96a323f4091de 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -1,7 +1,7 @@ -from .windows import cosine_window, exponential_window, gaussian_window +from .windows import cosine, exponential, gaussian __all__ = [ - 'cosine_window', - 'exponential_window', - 'gaussian_window', + 'cosine', + 'exponential', + 'gaussian', ] diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index ba9d5984d4def..5eacf09e541cb 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -4,9 +4,9 @@ from torch.types import _dtype, _device, _layout __all__ = [ - 'cosine_window', - 'exponential_window', - 'gaussian_window', + 'cosine', + 'exponential', + 'gaussian', ] @@ -35,30 +35,32 @@ def is_complex_type(t: _dtype) -> bool: raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') -def exponential_window(window_length: int, - periodic: bool = True, - center: float = None, - tau: float = 1.0, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, - requires_grad: bool = False) -> Tensor: +def exponential(window_length: int, + periodic: bool = True, + center: float = None, + tau: float = 1.0, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None, + requires_grad: bool = False) -> Tensor: r"""Computes a window with an exponential form. - The window is also known as Poisson window. + Also known as Poisson window. The exponential window is defined as follows: .. math:: - w(n) = e^{-\frac{|n - center|}{\tau}} + w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`,returns a symmetric window suitable for use in filter design. - center (float, optional): this value defines where the center of the window will be located. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + center (float, optional): his value defines where the center of the window will be located. In other words, at which sample the peak of the window can be found. - tau (float, optional): the decay value. For `center = 0`, it's suggested to use `tau = -(M - 1) / ln(x)`, - if `x` is the fraction of the window remaining at the end. + Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + tau (float, optional): the decay value. For `center = 0`, it's suggested to use + :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, if `x` is the fraction of the window remaining at the end. + Default: 1.0. Keyword args: dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. @@ -71,17 +73,14 @@ def exponential_window(window_length: int, :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - Returns: - (torch.Tensor): window in the form of a tensor. - Examples: >>> # Generate an exponential window without keyword args. - >>> torch.signal.windows.exponential_window(10) + >>> torch.signal.windows.exponential(10) tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, 0.0183]) >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential_window(10, tau=.5, periodic=False) + >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) """ @@ -111,16 +110,16 @@ def exponential_window(window_length: int, return torch.exp(-torch.abs(k) / tau) -def cosine_window(window_length: int, - periodic: bool = True, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, - requires_grad: bool = False) -> Tensor: +def cosine(window_length: int, + periodic: bool = True, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None, + requires_grad: bool = False) -> Tensor: r"""Computes a window with a simple cosine waveform. + Also known as the sine window. - The cosine window is also known as the sine window due to the following - equality: + The cosine window is defined as follows: .. math:: w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} @@ -130,8 +129,8 @@ def cosine_window(window_length: int, Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. - periodic (bool): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. Keyword args: dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. @@ -144,17 +143,14 @@ def cosine_window(window_length: int, :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - Returns: - (torch.Tensor): window in the form of a tensor. - Examples: >>> # Generate a cosine window without keyword args. - >>> torch.signal.windows.cosine_window(10) + >>> torch.signal.windows.cosine(10) tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, 0.4154]) >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine_window(10, periodic=False) + >>> torch.signal.windows.cosine(10,periodic=False) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) """ @@ -178,26 +174,27 @@ def cosine_window(window_length: int, return window[:-1] if periodic else window -def gaussian_window(window_length: int, - periodic: bool = True, - std: float = 0.5, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, - requires_grad: bool = False) -> Tensor: +def gaussian(window_length: int, + periodic: bool = True, + std: float = 0.5, + dtype: _dtype = None, + layout: _layout = torch.strided, + device: _device = None, + requires_grad: bool = False) -> Tensor: r"""Computes a window with a gaussian waveform. The gaussian window is defined as follows: .. math:: - w(n) = e^{-\left(\frac{n}{2\sigma}\right)^2} + w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True` std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 0.5. Keyword args: dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. @@ -210,20 +207,18 @@ def gaussian_window(window_length: int, :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - Returns: - (torch.Tensor): window in the form of a tensor. - Examples: >>> # Generate a gaussian window without keyword args. - >>> torch.signal.windows.gaussian_window(10) + >>> torch.signal.windows.gaussian(10) tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian_window(10, std=0.9, periodic=False) + >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) """ + if dtype is None: dtype = torch.get_default_dtype() From bf5f8bb4e63b60dd5920794f09b6d929e9cbf42d Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:04 -0300 Subject: [PATCH 28/76] Update docstring --- torch/signal/windows/windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 5eacf09e541cb..a7e8c120df4af 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -43,7 +43,7 @@ def exponential(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - r"""Computes a window with an exponential form. + r"""Computes a window with an exponential waveform. Also known as Poisson window. The exponential window is defined as follows: From e9deb0ed36d981fb933ff4de40e2539e87d193ce Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:04 -0300 Subject: [PATCH 29/76] Add docstr differently --- torch/signal/windows/__init__.py | 140 +++++++++++++++++++++++++++++++ torch/signal/windows/windows.py | 124 +-------------------------- 2 files changed, 144 insertions(+), 120 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 96a323f4091de..aa330514227e0 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -1,7 +1,147 @@ +import warnings + from .windows import cosine, exponential, gaussian +from torch._torch_docs import factory_common_args + __all__ = [ 'cosine', 'exponential', 'gaussian', ] + + +def add_docstr(function, docstr): + function.__doc__ = docstr + + +add_docstr( + cosine, + r""" +Computes a window with a simple cosine waveform. +Also known as the sine window. + +The cosine window is defined as follows: + +.. math:: + w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} + +Where `M` is the length of the window. + """ + + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a cosine window without keyword args. + >>> torch.signal.windows.cosine(10) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) + + >>> # Generate a symmetric cosine window. + >>> torch.signal.windows.cosine(10,periodic=False) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) +""".format( + **factory_common_args + ), +) + +add_docstr( + exponential, + r""" +Computes a window with an exponential waveform. +Also known as Poisson window. + +The exponential window is defined as follows: + +.. math:: + w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} + """ + + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the ee window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + center (float, optional): his value defines where the center of the window will be located. + In other words, at which sample the peak of the window can be found. + Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + tau (float, optional): the decay value. + For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, + if `x` is the fraction of the window remaining at the end. Default: 1.0. + """ + + r""" + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate an exponential window without keyword args. + >>> torch.signal.windows.exponential(10) + tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, + 0.0183]) + + >>> # Generate a symmetric exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) + tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, + 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) +""".format( + **factory_common_args + ), +) + +add_docstr( + gaussian, + r""" +Computes a window with a gaussian waveform. + +The gaussian window is defined as follows: + +.. math:: + w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} + """ + + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True` + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 0.5. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a gaussian window without keyword args. + >>> torch.signal.windows.gaussian(10) + tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) + tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, + 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) +""".format( + **factory_common_args + ), +) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index a7e8c120df4af..e7923b85b9a5d 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -29,7 +29,7 @@ def is_complex_type(t: _dtype) -> bool: if window_length < 0: raise RuntimeError(f'{function_name} requires non-negative window_length, got window_length={window_length}') - if layout is torch.sparse_coo: + if layout is not torch.strided: raise RuntimeError(f'{function_name} is not implemented for sparse types, got: {layout}') if not is_floating_type(dtype) and not is_complex_type(dtype): raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') @@ -43,47 +43,6 @@ def exponential(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - r"""Computes a window with an exponential waveform. - Also known as Poisson window. - - The exponential window is defined as follows: - - .. math:: - w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} - - Args: - window_length (int): the length of the output window. In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - center (float, optional): his value defines where the center of the window will be located. - In other words, at which sample the peak of the window can be found. - Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. For `center = 0`, it's suggested to use - :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, if `x` is the fraction of the window remaining at the end. - Default: 1.0. - - Keyword args: - dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. - Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. - Only `torch.strided` (dense layout) is supported. - device (:class:`torch.device`, optional): the desired device of returned tensor. - Default: if ``None``, uses the current device for the default tensor type - (see :func:`torch.set_default_tensor_type`). - :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. - requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - - Examples: - >>> # Generate an exponential window without keyword args. - >>> torch.signal.windows.exponential(10) - tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, - 0.0183]) - - >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) - tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, - 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - """ if dtype is None: dtype = torch.get_default_dtype() @@ -116,44 +75,6 @@ def cosine(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - r"""Computes a window with a simple cosine waveform. - Also known as the sine window. - - The cosine window is defined as follows: - - .. math:: - w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} - - Where `M` is the window length. - - Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - - Keyword args: - dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. - Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. - Only `torch.strided` (dense layout) is supported. - device (:class:`torch.device`, optional): the desired device of returned tensor. - Default: if ``None``, uses the current device for the default tensor type - (see :func:`torch.set_default_tensor_type`). - :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. - requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - - Examples: - >>> # Generate a cosine window without keyword args. - >>> torch.signal.windows.cosine(10) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) - - >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine(10,periodic=False) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) - """ if dtype is None: dtype = torch.get_default_dtype() @@ -168,8 +89,9 @@ def cosine(window_length: int, if periodic: window_length += 1 - k = torch.arange(window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - window = torch.sin(torch.pi / window_length * (k + .5)) + start = .5 + k = torch.arange(start, start + window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + window = torch.sin(torch.pi / window_length * k) return window[:-1] if periodic else window @@ -181,44 +103,6 @@ def gaussian(window_length: int, layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: - r"""Computes a window with a gaussian waveform. - - The gaussian window is defined as follows: - - .. math:: - w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} - - Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True` - std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. - Default: 0.5. - - Keyword args: - dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor. - Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`). - layout (:class:`torch.layout`, optional): the desired layout of returned window tensor. - Only `torch.strided` (dense layout) is supported. - device (:class:`torch.device`, optional): the desired device of returned tensor. - Default: if ``None``, uses the current device for the default tensor type - (see :func:`torch.set_default_tensor_type`). - :attr:`device` will be the CPU for CPU tensor types and the current CUDA device for CUDA tensor types. - requires_grad (bool, optional): If autograd should record operations on the returned tensor. Default: ``False``. - - Examples: - >>> # Generate a gaussian window without keyword args. - >>> torch.signal.windows.gaussian(10) - tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - - >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) - tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, - 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) - """ - if dtype is None: dtype = torch.get_default_dtype() From 0bb072ff8bf55fe0ba2b7d646de1b683bddee68f Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:05 -0300 Subject: [PATCH 30/76] Update cosine --- torch/signal/windows/__init__.py | 4 ++++ torch/signal/windows/windows.py | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index aa330514227e0..1788b4148b947 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -52,6 +52,10 @@ def add_docstr(function, docstr): >>> torch.signal.windows.cosine(10,periodic=False) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) + +.. note:: + The window is normalized with the maximum value equal to 1, however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. """.format( **factory_common_args ), diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index e7923b85b9a5d..a9535322ade8e 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -86,14 +86,14 @@ def cosine(window_length: int, if window_length == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if periodic: - window_length += 1 - start = .5 - k = torch.arange(start, start + window_length, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - window = torch.sin(torch.pi / window_length * k) - - return window[:-1] if periodic else window + k = torch.arange(start, + start+window_length, + dtype=dtype, + layout=layout, + device=device, + requires_grad=requires_grad) + return torch.sin(torch.pi / (window_length + 1 if periodic else window_length) * k) def gaussian(window_length: int, From 330ba1d683cf8547b076e22213b0fb71a0d9fdb5 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:05 -0300 Subject: [PATCH 31/76] Add note --- torch/signal/windows/__init__.py | 22 +++++++++++++++------- torch/signal/windows/windows.py | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 1788b4148b947..1d2718ecdf202 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -29,7 +29,7 @@ def add_docstr(function, docstr): Where `M` is the length of the window. """ + r""" - + Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. @@ -54,7 +54,7 @@ def add_docstr(function, docstr): 0.1564]) .. note:: - The window is normalized with the maximum value equal to 1, however, the 1 doesn't appear if `M` is even + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even and `periodic` is `False`. """.format( **factory_common_args @@ -73,17 +73,17 @@ def add_docstr(function, docstr): w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} """ + r""" - + Args: - window_length (int): the length of the output window. + window_length (int): the length of the output window. In other words, the number of points of the ee window. periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. center (float, optional): his value defines where the center of the window will be located. In other words, at which sample the peak of the window can be found. Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. - For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, + tau (float, optional): the decay value. + For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, if `x` is the fraction of the window remaining at the end. Default: 1.0. """ + r""" @@ -104,6 +104,10 @@ def add_docstr(function, docstr): >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. """.format( **factory_common_args ), @@ -120,7 +124,7 @@ def add_docstr(function, docstr): w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} """ + r""" - + Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. @@ -145,6 +149,10 @@ def add_docstr(function, docstr): >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. """.format( **factory_common_args ), diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index a9535322ade8e..0e50ee5375f69 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -88,7 +88,7 @@ def cosine(window_length: int, start = .5 k = torch.arange(start, - start+window_length, + start + window_length, dtype=dtype, layout=layout, device=device, From 1960b2b247de6af8db313def728453d01448d203 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:06 -0300 Subject: [PATCH 32/76] Update signature --- torch/signal/windows/__init__.py | 227 +++++++++++++++---------------- 1 file changed, 109 insertions(+), 118 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 1d2718ecdf202..9098b5b3ef9a5 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -11,13 +11,11 @@ ] -def add_docstr(function, docstr): +def _add_docstr(function, docstr): function.__doc__ = docstr -add_docstr( - cosine, - r""" +_add_docstr(cosine, r""" Computes a window with a simple cosine waveform. Also known as the sine window. @@ -28,42 +26,39 @@ def add_docstr(function, docstr): Where `M` is the length of the window. """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate a cosine window without keyword args. - >>> torch.signal.windows.cosine(10) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) - - >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine(10,periodic=False) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. -""".format( - **factory_common_args - ), -) - -add_docstr( - exponential, - r""" + r""" + + Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + + Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + + Examples: + >>> # Generate a cosine window without keyword args. + >>> torch.signal.windows.cosine(10) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) + + >>> # Generate a symmetric cosine window. + >>> torch.signal.windows.cosine(10,periodic=False) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) + + .. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + """.format( + **factory_common_args + )) + +_add_docstr(exponential, r""" Computes a window with an exponential waveform. Also known as Poisson window. @@ -72,50 +67,47 @@ def add_docstr(function, docstr): .. math:: w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the ee window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - center (float, optional): his value defines where the center of the window will be located. - In other words, at which sample the peak of the window can be found. - Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. - For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, - if `x` is the fraction of the window remaining at the end. Default: 1.0. - """ + - r""" - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate an exponential window without keyword args. - >>> torch.signal.windows.exponential(10) - tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, - 0.0183]) - - >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) - tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, - 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. -""".format( - **factory_common_args - ), -) - -add_docstr( - gaussian, - r""" + r""" + + Args: + window_length (int): the length of the output window. + In other words, the number of points of the ee window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + center (float, optional): his value defines where the center of the window will be located. + In other words, at which sample the peak of the window can be found. + Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + tau (float, optional): the decay value. + For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, + if `x` is the fraction of the window remaining at the end. Default: 1.0. + """ + + r""" + + Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + + Examples: + >>> # Generate an exponential window without keyword args. + >>> torch.signal.windows.exponential(10) + tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, + 0.0183]) + + >>> # Generate a symmetric exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) + tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, + 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) + + .. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + """.format( + **factory_common_args + )) + +_add_docstr(gaussian, r""" Computes a window with a gaussian waveform. The gaussian window is defined as follows: @@ -123,37 +115,36 @@ def add_docstr(function, docstr): .. math:: w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True` - std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. - Default: 0.5. - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate a gaussian window without keyword args. - >>> torch.signal.windows.gaussian(10) - tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - - >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) - tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, - 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. -""".format( - **factory_common_args - ), -) + r""" + + Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True` + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 0.5. + + Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + + Examples: + >>> # Generate a gaussian window without keyword args. + >>> torch.signal.windows.gaussian(10) + tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) + tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, + 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) + + .. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + """.format( + **factory_common_args + )) From c69bddd6d64cd863daa2699a747e3292e96193d6 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:06 -0300 Subject: [PATCH 33/76] Fix lint --- torch/signal/windows/__init__.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 9098b5b3ef9a5..7171705e84a6c 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -27,30 +27,30 @@ def _add_docstr(function, docstr): Where `M` is the length of the window. """ + r""" - + Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - + Keyword args: {dtype} {layout} {device} {requires_grad} - + Examples: >>> # Generate a cosine window without keyword args. >>> torch.signal.windows.cosine(10) tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, 0.4154]) - + >>> # Generate a symmetric cosine window. >>> torch.signal.windows.cosine(10,periodic=False) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) - + .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even and `periodic` is `False`. @@ -68,7 +68,7 @@ def _add_docstr(function, docstr): w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} """ + r""" - + Args: window_length (int): the length of the output window. In other words, the number of points of the ee window. @@ -82,24 +82,24 @@ def _add_docstr(function, docstr): if `x` is the fraction of the window remaining at the end. Default: 1.0. """ + r""" - + Keyword args: {dtype} {layout} {device} {requires_grad} - + Examples: >>> # Generate an exponential window without keyword args. >>> torch.signal.windows.exponential(10) tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, 0.0183]) - + >>> # Generate a symmetric exponential window and decay factor equal to .5 >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - + .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even and `periodic` is `False`. @@ -116,7 +116,7 @@ def _add_docstr(function, docstr): w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} """ + r""" - + Args: window_length (int): the length of the output window. In other words, the number of points of the cosine window. @@ -124,24 +124,24 @@ def _add_docstr(function, docstr): If `False`, returns a symmetric window suitable for use in filter design. Default: `True` std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. Default: 0.5. - + Keyword args: {dtype} {layout} {device} {requires_grad} - + Examples: >>> # Generate a gaussian window without keyword args. >>> torch.signal.windows.gaussian(10) tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) - + .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even and `periodic` is `False`. From 75a80e7bee61dfb768822a623d74b59257788076 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:07 -0300 Subject: [PATCH 34/76] Update docs --- torch/signal/windows/__init__.py | 225 ++++++++++++++++--------------- 1 file changed, 117 insertions(+), 108 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 7171705e84a6c..b38634784baf3 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -15,7 +15,9 @@ def _add_docstr(function, docstr): function.__doc__ = docstr -_add_docstr(cosine, r""" +_add_docstr( + cosine, + r""" Computes a window with a simple cosine waveform. Also known as the sine window. @@ -26,39 +28,42 @@ def _add_docstr(function, docstr): Where `M` is the length of the window. """ + - r""" - - Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - - Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - - Examples: - >>> # Generate a cosine window without keyword args. - >>> torch.signal.windows.cosine(10) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) - - >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine(10,periodic=False) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) - - .. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - """.format( - **factory_common_args - )) - -_add_docstr(exponential, r""" + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a cosine window without keyword args. + >>> torch.signal.windows.cosine(10) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) + + >>> # Generate a symmetric cosine window. + >>> torch.signal.windows.cosine(10,periodic=False) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. +""".format( + **factory_common_args + ) +) + +_add_docstr( + exponential, + r""" Computes a window with an exponential waveform. Also known as Poisson window. @@ -67,47 +72,50 @@ def _add_docstr(function, docstr): .. math:: w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} """ + - r""" - - Args: - window_length (int): the length of the output window. - In other words, the number of points of the ee window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - center (float, optional): his value defines where the center of the window will be located. - In other words, at which sample the peak of the window can be found. - Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. - For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, - if `x` is the fraction of the window remaining at the end. Default: 1.0. - """ + - r""" - - Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - - Examples: - >>> # Generate an exponential window without keyword args. - >>> torch.signal.windows.exponential(10) - tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, - 0.0183]) - - >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) - tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, - 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - - .. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - """.format( - **factory_common_args - )) - -_add_docstr(gaussian, r""" + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the ee window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + center (float, optional): his value defines where the center of the window will be located. + In other words, at which sample the peak of the window can be found. + Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + tau (float, optional): the decay value. + For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, + if `x` is the fraction of the window remaining at the end. Default: 1.0. + """ + + r""" + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate an exponential window without keyword args. + >>> torch.signal.windows.exponential(10) + tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, + 0.0183]) + + >>> # Generate a symmetric exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) + tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, + 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + """.format( + **factory_common_args + ) +) + +_add_docstr( + gaussian, + r""" Computes a window with a gaussian waveform. The gaussian window is defined as follows: @@ -115,36 +123,37 @@ def _add_docstr(function, docstr): .. math:: w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} """ + - r""" - - Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True` - std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. - Default: 0.5. - - Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - - Examples: - >>> # Generate a gaussian window without keyword args. - >>> torch.signal.windows.gaussian(10) - tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - - >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) - tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, - 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) - - .. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - """.format( - **factory_common_args - )) + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True` + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 0.5. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a gaussian window without keyword args. + >>> torch.signal.windows.gaussian(10) + tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) + tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, + 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. +""".format( + **factory_common_args + ) +) From 3b9ddd88dbd68bab18d5c8c2aaa5a531c7fbca25 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:07 -0300 Subject: [PATCH 35/76] Fix numeric errors --- torch/signal/windows/windows.py | 72 ++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 0e50ee5375f69..c513bb009f9f9 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,4 +1,7 @@ +import warnings + import torch +import numpy as np from torch import Tensor from torch.types import _dtype, _device, _layout @@ -35,6 +38,20 @@ def is_complex_type(t: _dtype) -> bool: raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') +def _window_length_check(desired_length, output_length): + r"""Performs window length check. + This function should be called after computing windows with `torch.arange` + if the step is floating point. + + Args: + desired_length (int): desired length of the window. + output_length (int): output length of the window. + """ + if desired_length != output_length: + warnings.warn(('The difference in length is subject to floating points rounding errors.' + f'Expected length: {output_length}. Output length: {desired_length}')) + + def exponential(window_length: int, periodic: bool = True, center: float = None, @@ -46,7 +63,7 @@ def exponential(window_length: int, if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('exponential_window', window_length, dtype, layout) + _window_function_checks('exponential', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -57,16 +74,24 @@ def exponential(window_length: int, if periodic and center is not None: raise ValueError('Center must be \'None\' for periodic equal True') + if tau <= 0: + raise ValueError(f'Tau cannot must be positive, got: {tau} instead.') + if center is None: center = -(window_length if periodic else window_length - 1) / 2.0 - k = torch.arange(start=center, - end=center + window_length, - dtype=dtype, layout=layout, + constant = 1 / tau + k = torch.arange(center * constant, + (center * constant + window_length * constant), # Distributive property does not apply + constant, + dtype=dtype, + layout=layout, device=device, requires_grad=requires_grad) - return torch.exp(-torch.abs(k) / tau) + _window_length_check(window_length, k.size()[0]) + + return torch.exp(-torch.abs(k)) def cosine(window_length: int, @@ -78,7 +103,7 @@ def cosine(window_length: int, if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('cosine_window', window_length, dtype, layout) + _window_function_checks('cosine', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -86,19 +111,27 @@ def cosine(window_length: int, if window_length == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - start = .5 - k = torch.arange(start, - start + window_length, + start = 0.5 + constant = torch.pi / (window_length + 1 if periodic else window_length) + + """ + Note that non-integer step is subject to floating point rounding errors when comparing against end; + to avoid inconsistency, we advise adding a small epsilon to end in such cases. + """ + k = torch.arange(start * constant, + (start * constant + window_length * constant), # Distributive property does not apply + step=constant, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - return torch.sin(torch.pi / (window_length + 1 if periodic else window_length) * k) + + return torch.sin(k) def gaussian(window_length: int, periodic: bool = True, - std: float = 0.5, + std: float = 1., dtype: _dtype = None, layout: _layout = torch.strided, device: _device = None, @@ -106,7 +139,7 @@ def gaussian(window_length: int, if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('cosine_window', window_length, dtype, layout) + _window_function_checks('gaussian', window_length, dtype, layout) if window_length == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) @@ -116,11 +149,20 @@ def gaussian(window_length: int, start = -(window_length if periodic else window_length - 1) / 2.0 - k = torch.arange(start, - start + window_length, + constant = 1 / (std * np.sqrt(2)) + + """ + Note that non-integer step is subject to floating point rounding errors when comparing against end; + to avoid inconsistency, we advise adding a small epsilon to end in such cases. + """ + k = torch.arange(start * constant, + (start * constant + window_length * constant), # Distributive property does not apply here. + step=constant, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - return torch.exp(-(k / std) ** 2 / 2) + _window_length_check(window_length, k.size()[0]) + + return torch.exp(-k ** 2) From 0f0db71c48645e2c55d5d5136666e1050bf33f6d Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:08 -0300 Subject: [PATCH 36/76] Fix numeric errors --- torch/signal/windows/windows.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index c513bb009f9f9..9b69c91692502 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -12,6 +12,8 @@ 'gaussian', ] +_eps = 1e-10 # Used to fix floating point errors + def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout) -> None: r"""Performs common checks for all the defined windows. @@ -82,7 +84,7 @@ def exponential(window_length: int, constant = 1 / tau k = torch.arange(center * constant, - (center * constant + window_length * constant), # Distributive property does not apply + (center + (window_length - 1)) * constant + _eps, constant, dtype=dtype, layout=layout, @@ -119,7 +121,7 @@ def cosine(window_length: int, to avoid inconsistency, we advise adding a small epsilon to end in such cases. """ k = torch.arange(start * constant, - (start * constant + window_length * constant), # Distributive property does not apply + (start + (window_length - 1)) * constant + _eps, step=constant, dtype=dtype, layout=layout, @@ -156,7 +158,7 @@ def gaussian(window_length: int, to avoid inconsistency, we advise adding a small epsilon to end in such cases. """ k = torch.arange(start * constant, - (start * constant + window_length * constant), # Distributive property does not apply here. + (start + (window_length - 1)) * constant + _eps, step=constant, dtype=dtype, layout=layout, From 65d2f35a633b8bf9331ba1f30e2ac678673dfd04 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:08 -0300 Subject: [PATCH 37/76] Add comment --- torch/signal/windows/windows.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 9b69c91692502..1cbe95601ec71 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -83,6 +83,11 @@ def exponential(window_length: int, center = -(window_length if periodic else window_length - 1) / 2.0 constant = 1 / tau + + """ + Note that non-integer step is subject to floating point rounding errors when comparing against end; + to avoid inconsistency, we advise adding a small epsilon to end in such cases. + """ k = torch.arange(center * constant, (center + (window_length - 1)) * constant + _eps, constant, From a00a9e4a470f968a296b76f9eaa895f3b7286b45 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:08 -0300 Subject: [PATCH 38/76] Fix lint --- torch/signal/windows/windows.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 1cbe95601ec71..8d05b2a643536 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -85,7 +85,7 @@ def exponential(window_length: int, constant = 1 / tau """ - Note that non-integer step is subject to floating point rounding errors when comparing against end; + Note that non-integer step is subject to floating point rounding errors when comparing against end; to avoid inconsistency, we advise adding a small epsilon to end in such cases. """ k = torch.arange(center * constant, @@ -122,7 +122,7 @@ def cosine(window_length: int, constant = torch.pi / (window_length + 1 if periodic else window_length) """ - Note that non-integer step is subject to floating point rounding errors when comparing against end; + Note that non-integer step is subject to floating point rounding errors when comparing against end; to avoid inconsistency, we advise adding a small epsilon to end in such cases. """ k = torch.arange(start * constant, @@ -133,6 +133,8 @@ def cosine(window_length: int, device=device, requires_grad=requires_grad) + _window_length_check(window_length, k.size()[0]) + return torch.sin(k) @@ -159,7 +161,7 @@ def gaussian(window_length: int, constant = 1 / (std * np.sqrt(2)) """ - Note that non-integer step is subject to floating point rounding errors when comparing against end; + Note that non-integer step is subject to floating point rounding errors when comparing against end; to avoid inconsistency, we advise adding a small epsilon to end in such cases. """ k = torch.arange(start * constant, From 9b88ffe1c13478cb14e2b3cb7c9753fe6652ac19 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:14:09 -0300 Subject: [PATCH 39/76] Address review --- torch/signal/windows/__init__.py | 24 +++++++++--------- torch/signal/windows/windows.py | 43 ++++++++------------------------ 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index b38634784baf3..9240d98c0dd1b 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -36,6 +36,10 @@ def _add_docstr(function, docstr): periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + Keyword args: {dtype} {layout} @@ -52,10 +56,6 @@ def _add_docstr(function, docstr): >>> torch.signal.windows.cosine(10,periodic=False) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. """.format( **factory_common_args ) @@ -88,6 +88,10 @@ def _add_docstr(function, docstr): """ + r""" +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + Keyword args: {dtype} {layout} @@ -104,10 +108,6 @@ def _add_docstr(function, docstr): >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. """.format( **factory_common_args ) @@ -133,6 +133,10 @@ def _add_docstr(function, docstr): std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. Default: 0.5. +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + Keyword args: {dtype} {layout} @@ -149,10 +153,6 @@ def _add_docstr(function, docstr): >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. """.format( **factory_common_args ) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 8d05b2a643536..d5ddfff084750 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -4,6 +4,7 @@ import numpy as np from torch import Tensor +from torch._torch_docs import factory_common_args from torch.types import _dtype, _device, _layout __all__ = [ @@ -12,8 +13,6 @@ 'gaussian', ] -_eps = 1e-10 # Used to fix floating point errors - def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout) -> None: r"""Performs common checks for all the defined windows. @@ -40,20 +39,6 @@ def is_complex_type(t: _dtype) -> bool: raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') -def _window_length_check(desired_length, output_length): - r"""Performs window length check. - This function should be called after computing windows with `torch.arange` - if the step is floating point. - - Args: - desired_length (int): desired length of the window. - output_length (int): output length of the window. - """ - if desired_length != output_length: - warnings.warn(('The difference in length is subject to floating points rounding errors.' - f'Expected length: {output_length}. Output length: {desired_length}')) - - def exponential(window_length: int, periodic: bool = True, center: float = None, @@ -86,18 +71,16 @@ def exponential(window_length: int, """ Note that non-integer step is subject to floating point rounding errors when comparing against end; - to avoid inconsistency, we advise adding a small epsilon to end in such cases. + thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ - k = torch.arange(center * constant, - (center + (window_length - 1)) * constant + _eps, - constant, + k = torch.arange(start=center * constant, + end=(center + (window_length - 1)) * constant + constant / 2, + step=constant, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - _window_length_check(window_length, k.size()[0]) - return torch.exp(-torch.abs(k)) @@ -123,18 +106,16 @@ def cosine(window_length: int, """ Note that non-integer step is subject to floating point rounding errors when comparing against end; - to avoid inconsistency, we advise adding a small epsilon to end in such cases. + thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ - k = torch.arange(start * constant, - (start + (window_length - 1)) * constant + _eps, + k = torch.arange(start=start * constant, + end=(start + (window_length - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - _window_length_check(window_length, k.size()[0]) - return torch.sin(k) @@ -162,16 +143,14 @@ def gaussian(window_length: int, """ Note that non-integer step is subject to floating point rounding errors when comparing against end; - to avoid inconsistency, we advise adding a small epsilon to end in such cases. + thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ - k = torch.arange(start * constant, - (start + (window_length - 1)) * constant + _eps, + k = torch.arange(start=start * constant, + end=(start + (window_length - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - _window_length_check(window_length, k.size()[0]) - return torch.exp(-k ** 2) From cb280572ff2689cab00bad9b540a458fe67a4ce9 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:07 -0300 Subject: [PATCH 40/76] Move docstrs --- test/test_signal.py | 81 ++++++ test/test_tensor_creation_ops.py | 34 --- torch/signal/windows/__init__.py | 149 ----------- torch/signal/windows/windows.py | 176 ++++++++++++- .../_internal/opinfo/definitions/__init__.py | 10 +- .../_internal/opinfo/definitions/signal.py | 248 ++++++++++++++++++ 6 files changed, 506 insertions(+), 192 deletions(-) create mode 100644 test/test_signal.py create mode 100644 torch/testing/_internal/opinfo/definitions/signal.py diff --git a/test/test_signal.py b/test/test_signal.py new file mode 100644 index 0000000000000..84b60a4cc35cc --- /dev/null +++ b/test/test_signal.py @@ -0,0 +1,81 @@ +# Owner(s): ["module: signal"] + +import random + +import torch +import unittest +import re + +from torch.testing._internal.common_utils import ( + TestCase, run_tests +) +from torch.testing._internal.common_device_type import ( + ops, instantiate_device_type_tests, OpDTypes +) +from torch.testing._internal.common_methods_invocations import ( + precisionOverride, signal_funcs +) +from torch.testing._internal.opinfo.core import OpInfo + + +class TestSignalWindows(TestCase): + exact_dtype = False + + supported_windows = 'cosine|exponential|gaussian' + + def _test_window(self, device, dtype, op: OpInfo, **kwargs): + if op.ref is None: + raise unittest.SkipTest("No reference implementation") + + sample_inputs = op.sample_inputs(device, dtype, **kwargs) + + for sample_input in sample_inputs: + window_size = sample_input.input + window_name = re.search(self.supported_windows, op.name).group(0) + periodic = sample_input.kwargs.pop('periodic') + + expected = torch.from_numpy( + op.ref((window_name, *(sample_input.kwargs.values())), window_size, fftbins=periodic) + ) + actual = op(window_size, periodic=periodic, **sample_input.kwargs) + self.assertEqual(actual, expected, exact_dtype=self.exact_dtype) + self.assertTrue(op(3, requires_grad=True).requires_grad) + self.assertFalse(op(3).requires_grad) + + def _test_window_errors(self, device, op): + error_inputs = op.error_inputs(device) + + for error_input in error_inputs: + sample_input = error_input.sample_input + with self.assertRaisesRegex(error_input.error_type, error_input.error_regex): + op(sample_input.input, *sample_input.args, **sample_input.kwargs) + + @ops([op for op in signal_funcs if 'windows' in op.name], dtypes=OpDTypes.none) + def test_window_errors(self, device, op): + self._test_window_errors(device, op) + + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @ops([op for op in signal_funcs if 'windows.cosine' in op.name], + allowed_dtypes=(torch.float, torch.double, torch.long)) + def test_cosine_window(self, device, dtype, op): + self._test_window(device, dtype, op) + + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @ops([op for op in signal_funcs if 'windows.exponential' in op.name], + allowed_dtypes=(torch.float, torch.double)) + def test_exponential_window(self, device, dtype, op): + for _ in range(50): + self._test_window(device, dtype, op, center=None, tau=random.uniform(0, 10)) + + @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) + @ops([op for op in signal_funcs if 'windows.gaussian' in op.name], + allowed_dtypes=(torch.float, torch.double, torch.long)) + def test_gaussian_window(self, device, dtype, op): + for _ in range(50): + self._test_window(device, dtype, op, std=random.uniform(0, 3)) + + +instantiate_device_type_tests(TestSignalWindows, globals()) + +if __name__ == '__main__': + run_tests() diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index d723524167dd5..1fcb3a1ffef92 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2669,40 +2669,6 @@ def test_kaiser_window(self, device, dtype): for num_test in range(50): self._test_signal_window_functions('kaiser', dtype, device, beta=random.random() * 30) - @onlyNativeDeviceTypes - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @unittest.skipIf(not TEST_SCIPY, "Scipy not found") - @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) - @dtypes(torch.float, torch.double, torch.long) - def test_cosine_window(self, device, dtype): - for num_test in range(50): - self._test_signal_window_functions('cosine', dtype, device) - - @onlyNativeDeviceTypes - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @unittest.skipIf(not TEST_SCIPY, "Scipy not found") - @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) - @dtypes(torch.float, torch.double, torch.long) - def test_exponential_window(self, device, dtype): - for num_test in range(50): - self._test_signal_window_functions( - 'exponential', - dtype, - device, - center=None, - tau=round(random.uniform(0, 2), 2), - ) - - @onlyNativeDeviceTypes - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @unittest.skipIf(not TEST_SCIPY, "Scipy not found") - @dtypesIfCUDA(torch.float, torch.double, torch.bfloat16, torch.half, torch.long) - @dtypes(torch.float, torch.double, torch.long) - def test_gaussian_window(self, device, dtype): - for num_test in range(50): - self._test_signal_window_functions('gaussian', dtype, device, std=random.random() * 30) - - def test_tensor_factories_empty(self, device): # ensure we can create empty tensors from each factory function shapes = [(5, 0, 1), (0,), (0, 0, 1, 0, 2, 0, 0)] diff --git a/torch/signal/windows/__init__.py b/torch/signal/windows/__init__.py index 9240d98c0dd1b..9ccb9dcd1891a 100644 --- a/torch/signal/windows/__init__.py +++ b/torch/signal/windows/__init__.py @@ -2,158 +2,9 @@ from .windows import cosine, exponential, gaussian -from torch._torch_docs import factory_common_args __all__ = [ 'cosine', 'exponential', 'gaussian', ] - - -def _add_docstr(function, docstr): - function.__doc__ = docstr - - -_add_docstr( - cosine, - r""" -Computes a window with a simple cosine waveform. -Also known as the sine window. - -The cosine window is defined as follows: - -.. math:: - w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} - -Where `M` is the length of the window. - """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate a cosine window without keyword args. - >>> torch.signal.windows.cosine(10) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) - - >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine(10,periodic=False) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) -""".format( - **factory_common_args - ) -) - -_add_docstr( - exponential, - r""" -Computes a window with an exponential waveform. -Also known as Poisson window. - -The exponential window is defined as follows: - -.. math:: - w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} - """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the ee window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - center (float, optional): his value defines where the center of the window will be located. - In other words, at which sample the peak of the window can be found. - Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. - For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, - if `x` is the fraction of the window remaining at the end. Default: 1.0. - """ + - r""" - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate an exponential window without keyword args. - >>> torch.signal.windows.exponential(10) - tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, - 0.0183]) - - >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) - tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, - 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) - """.format( - **factory_common_args - ) -) - -_add_docstr( - gaussian, - r""" -Computes a window with a gaussian waveform. - -The gaussian window is defined as follows: - -.. math:: - w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} - """ + - r""" - -Args: - window_length (int): the length of the output window. - In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True` - std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. - Default: 0.5. - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. - -Keyword args: - {dtype} - {layout} - {device} - {requires_grad} - -Examples: - >>> # Generate a gaussian window without keyword args. - >>> torch.signal.windows.gaussian(10) - tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - - >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) - tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, - 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) -""".format( - **factory_common_args - ) -) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index d5ddfff084750..9613de352688d 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,5 +1,3 @@ -import warnings - import torch import numpy as np @@ -14,6 +12,25 @@ ] +def _add_docstr(*args): + r"""Adds docstrings to a given decorated function. + + Specially useful when then docstrings needs string interpolation, e.g., with + str.format(). + REMARK: Do not use this function if the docstring doesn't need string + interpolation, just write a conventional docstring. + + Args: + args (str): + """ + def decorator(o): + o.__doc__ = "" + for arg in args: + o.__doc__ += arg + return o + return decorator + + def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout) -> None: r"""Performs common checks for all the defined windows. This function should be called before computing any window @@ -32,17 +49,68 @@ def is_complex_type(t: _dtype) -> bool: return t == torch.complex64 or t == torch.complex128 or t == torch.complex32 if window_length < 0: - raise RuntimeError(f'{function_name} requires non-negative window_length, got window_length={window_length}') + raise ValueError(f'{function_name} requires non-negative window_length, got window_length={window_length}') if layout is not torch.strided: - raise RuntimeError(f'{function_name} is not implemented for sparse types, got: {layout}') + raise ValueError(f'{function_name} is not implemented for sparse types, got: {layout}') if not is_floating_type(dtype) and not is_complex_type(dtype): - raise RuntimeError(f'{function_name} expects floating point dtypes, got: {dtype}') - - + raise ValueError(f'{function_name} expects floating point dtypes, got: {dtype}') + + +@_add_docstr( + r""" +Computes a window with an exponential waveform. +Also known as Poisson window. + +The exponential window is defined as follows: + +.. math:: + w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} + """, + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the ee window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + center (float, optional): his value defines where the center of the window will be located. + In other words, at which sample the peak of the window can be found. + Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + tau (float, optional): the decay value. + For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, + if `x` is the fraction of the window remaining at the end. Default: 1.0. + """ + + r""" + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate an exponential window without keyword args. + >>> torch.signal.windows.exponential(10) + tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, + 0.0183]) + + >>> # Generate a symmetric exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) + tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, + 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) + """.format( + **factory_common_args + ), +) def exponential(window_length: int, periodic: bool = True, center: float = None, tau: float = 1.0, + *, dtype: _dtype = None, layout: _layout = torch.strided, device: _device = None, @@ -62,7 +130,7 @@ def exponential(window_length: int, raise ValueError('Center must be \'None\' for periodic equal True') if tau <= 0: - raise ValueError(f'Tau cannot must be positive, got: {tau} instead.') + raise ValueError(f'Tau must be positive, got: {tau} instead.') if center is None: center = -(window_length if periodic else window_length - 1) / 2.0 @@ -84,8 +152,53 @@ def exponential(window_length: int, return torch.exp(-torch.abs(k)) +@_add_docstr( + r""" +Computes a window with a simple cosine waveform. +Also known as the sine window. + +The cosine window is defined as follows: + +.. math:: + w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} + +Where `M` is the length of the window. + """, + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a cosine window without keyword args. + >>> torch.signal.windows.cosine(10) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) + + >>> # Generate a symmetric cosine window. + >>> torch.signal.windows.cosine(10,periodic=False) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) +""".format( + **factory_common_args + ), +) def cosine(window_length: int, periodic: bool = True, + *, dtype: _dtype = None, layout: _layout = torch.strided, device: _device = None, @@ -119,9 +232,53 @@ def cosine(window_length: int, return torch.sin(k) +@_add_docstr( + r""" +Computes a window with a gaussian waveform. + +The gaussian window is defined as follows: + +.. math:: + w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} + """, + r""" + +Args: + window_length (int): the length of the output window. + In other words, the number of points of the cosine window. + periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. + If `False`, returns a symmetric window suitable for use in filter design. Default: `True` + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 0.5. + +.. note:: + The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even + and `periodic` is `False`. + +Keyword args: + {dtype} + {layout} + {device} + {requires_grad} + +Examples: + >>> # Generate a gaussian window without keyword args. + >>> torch.signal.windows.gaussian(10) + tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + + >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) + tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, + 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) +""".format( + **factory_common_args + ), +) def gaussian(window_length: int, periodic: bool = True, std: float = 1., + *, dtype: _dtype = None, layout: _layout = torch.strided, device: _device = None, @@ -137,6 +294,9 @@ def gaussian(window_length: int, if window_length == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) + if std <= 0: + raise ValueError(f'Standard deviation must be positive, got: {std} instead.') + start = -(window_length if periodic else window_length - 1) / 2.0 constant = 1 / (std * np.sqrt(2)) diff --git a/torch/testing/_internal/opinfo/definitions/__init__.py b/torch/testing/_internal/opinfo/definitions/__init__.py index 7d81955f67e25..14698ec42a612 100644 --- a/torch/testing/_internal/opinfo/definitions/__init__.py +++ b/torch/testing/_internal/opinfo/definitions/__init__.py @@ -1,13 +1,20 @@ from typing import List from torch.testing._internal.opinfo.core import OpInfo -from torch.testing._internal.opinfo.definitions import _masked, fft, linalg, special +from torch.testing._internal.opinfo.definitions import ( + _masked, + fft, + linalg, + signal, + special, +) # Operator database op_db: List[OpInfo] = [ *fft.op_db, *linalg.op_db, *special.op_db, + *signal.op_db, *_masked.op_db, ] @@ -15,4 +22,5 @@ *fft.python_ref_db, *linalg.python_ref_db, *special.python_ref_db, + *signal.python_ref_db, ] diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py new file mode 100644 index 0000000000000..a52e5b5a822bb --- /dev/null +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -0,0 +1,248 @@ +import unittest +from typing import List + +import torch +from torch.testing._internal.common_dtype import all_types_and +from torch.testing._internal.common_utils import TEST_SCIPY +from torch.testing._internal.opinfo.core import ( + DecorateInfo, + ErrorInput, + OpInfo, + SampleInput, +) + +if TEST_SCIPY: + import scipy.signal + + +def _sample_input_windows(sample_input, *args, **kwargs): + for size in [0, 1, 2, 5, 10, 50, 100, 1024, 2048]: + for periodic in [True, False]: + kwargs.update( + { + "periodic": periodic, + } + ) + yield sample_input(size, args=args, kwargs=kwargs) + + +def sample_inputs_window(op_info, *args, **kwargs): + return _sample_input_windows(SampleInput, *args, **kwargs) + + +def error_inputs_window(op_info, *args, **kwargs): + yield ErrorInput( + SampleInput(-1, args=args, kwargs=kwargs), + error_type=ValueError, + error_regex="requires non-negative window_length, got window_length=-1", + ) + + tmp_kwargs = dict( + kwargs, + **{ + "layout": torch.sparse_coo, + }, + ) + + yield ErrorInput( + SampleInput(3, args=args, kwargs=tmp_kwargs), + error_type=ValueError, + error_regex="is not implemented for sparse types, got: torch.sparse_coo", + ) + + tmp_kwargs = kwargs + tmp_kwargs["dtype"] = torch.long + + yield ErrorInput( + SampleInput(3, args=args, kwargs=tmp_kwargs), + error_type=ValueError, + error_regex="expects floating point dtypes, got: torch.int64", + ) + + +def error_inputs_exponential_window(op_info, device, *args, **kwargs): + tmp_kwargs = dict(kwargs, **{"dtype": torch.float32, "device": device}) + + for error_input in error_inputs_window(op_info, *args, **kwargs): + yield error_input + + tmp_kwargs = dict(tmp_kwargs, **{"tau": -1}) + + yield ErrorInput( + SampleInput(3, args=args, kwargs=tmp_kwargs), + error_type=ValueError, + error_regex="Tau must be positive, got: -1 instead.", + ) + + tmp_kwargs = dict(tmp_kwargs, **{"center": 1}) + + yield ErrorInput( + SampleInput(3, args=args, kwargs=tmp_kwargs), + error_type=ValueError, + error_regex="Center must be 'None' for periodic equal True", + ) + + +def error_inputs_gaussian_window(op_info, device, *args, **kwargs): + tmp_kwargs = dict(kwargs, **{"dtype": torch.float32, "device": device}) + + for error_input in error_inputs_window(op_info, *args, **kwargs): + yield error_input + + tmp_kwargs = dict(tmp_kwargs, **{"std": -1}) + + yield ErrorInput( + SampleInput(3, args=args, kwargs=tmp_kwargs), + error_type=ValueError, + error_regex="Standard deviation must be positive, got: -1 instead.", + ) + + +op_db: List[OpInfo] = [ + OpInfo( + "signal.windows.cosine", + ref=scipy.signal.get_window if TEST_SCIPY else None, + dtypes=all_types_and(torch.float, torch.double, torch.long), + dtypesIfCUDA=all_types_and( + torch.float, torch.double, torch.bfloat16, torch.half, torch.long + ), + sample_inputs_func=sample_inputs_window, + error_inputs_func=error_inputs_window, + supports_out=False, + supports_autograd=False, + skips=( + DecorateInfo( + unittest.expectedFailure, + "TestNormalizeOperators", + "test_normalize_operator_exhaustive", + ), + # TODO: same as this? + # https://github.com/pytorch/pytorch/issues/81774 + # also see: arange, new_full + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, + "TestOperatorSignatures", + "test_get_torch_func_signature_exhaustive", + ), + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, "TestJit", "test_variant_consistency_jit" + ), + # skip these tests since we have non tensor input + DecorateInfo( + unittest.skip("Skipped!"), "TestCommon", "test_noncontiguous_samples" + ), + DecorateInfo( + unittest.skip("Skipped!"), + "TestCommon", + "test_variant_consistency_eager", + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_conj_view"), + DecorateInfo( + unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), + # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. + DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), + ), + ), + OpInfo( + "signal.windows.exponential", + ref=scipy.signal.get_window if TEST_SCIPY else None, + dtypes=all_types_and(torch.float, torch.double, torch.long), + dtypesIfCUDA=all_types_and( + torch.float, torch.double, torch.bfloat16, torch.half, torch.long + ), + sample_inputs_func=sample_inputs_window, + error_inputs_func=error_inputs_exponential_window, + supports_out=False, + supports_autograd=False, + skips=( + DecorateInfo( + unittest.expectedFailure, + "TestNormalizeOperators", + "test_normalize_operator_exhaustive", + ), + # TODO: same as this? + # https://github.com/pytorch/pytorch/issues/81774 + # also see: arange, new_full + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, + "TestOperatorSignatures", + "test_get_torch_func_signature_exhaustive", + ), + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, "TestJit", "test_variant_consistency_jit" + ), + # skip these tests since we have non tensor input + DecorateInfo( + unittest.skip("Skipped!"), "TestCommon", "test_noncontiguous_samples" + ), + DecorateInfo( + unittest.skip("Skipped!"), + "TestCommon", + "test_variant_consistency_eager", + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_conj_view"), + DecorateInfo( + unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), + # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. + DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), + ), + ), + OpInfo( + "signal.windows.gaussian", + ref=scipy.signal.get_window if TEST_SCIPY else None, + dtypes=all_types_and(torch.float, torch.double, torch.long), + dtypesIfCUDA=all_types_and( + torch.float, torch.double, torch.bfloat16, torch.half, torch.long + ), + sample_inputs_func=sample_inputs_window, + error_inputs_func=error_inputs_gaussian_window, + supports_out=False, + supports_autograd=False, + skips=( + DecorateInfo( + unittest.expectedFailure, + "TestNormalizeOperators", + "test_normalize_operator_exhaustive", + ), + # TODO: same as this? + # https://github.com/pytorch/pytorch/issues/81774 + # also see: arange, new_full + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, + "TestOperatorSignatures", + "test_get_torch_func_signature_exhaustive", + ), + # fails to match any schemas despite working in the interpreter + DecorateInfo( + unittest.expectedFailure, "TestJit", "test_variant_consistency_jit" + ), + # skip these tests since we have non tensor input + DecorateInfo( + unittest.skip("Skipped!"), "TestCommon", "test_noncontiguous_samples" + ), + DecorateInfo( + unittest.skip("Skipped!"), + "TestCommon", + "test_variant_consistency_eager", + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_conj_view"), + DecorateInfo( + unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" + ), + DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), + # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. + DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), + ), + ), +] + +python_ref_db: List[OpInfo] = [] From 23485c5f8f0e698cc29e0973250884872fc823ad Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:08 -0300 Subject: [PATCH 41/76] Revert test changes --- test/test_tensor_creation_ops.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_tensor_creation_ops.py b/test/test_tensor_creation_ops.py index 1fcb3a1ffef92..aab2645249698 100644 --- a/test/test_tensor_creation_ops.py +++ b/test/test_tensor_creation_ops.py @@ -2634,8 +2634,7 @@ def test_tensor_ctor_device_inference(self, device): def _test_signal_window_functions(self, name, dtype, device, **kwargs): import scipy.signal as signal - torch_method = getattr(torch.signal.windows, name) - + torch_method = getattr(torch, name + '_window') if not dtype.is_floating_point: with self.assertRaisesRegex(RuntimeError, r'floating point'): torch_method(3, dtype=dtype) From 7a6f2073a7dc632b346e949c9a59499679d45b33 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:08 -0300 Subject: [PATCH 42/76] Update OpInfo and tests --- test/test_signal.py | 42 +++--- .../_internal/opinfo/definitions/__init__.py | 1 - .../_internal/opinfo/definitions/signal.py | 127 ++++++++++-------- 3 files changed, 89 insertions(+), 81 deletions(-) diff --git a/test/test_signal.py b/test/test_signal.py index 84b60a4cc35cc..bc96056f3fe6a 100644 --- a/test/test_signal.py +++ b/test/test_signal.py @@ -1,7 +1,5 @@ # Owner(s): ["module: signal"] -import random - import torch import unittest import re @@ -13,7 +11,7 @@ ops, instantiate_device_type_tests, OpDTypes ) from torch.testing._internal.common_methods_invocations import ( - precisionOverride, signal_funcs + precisionOverride, op_db ) from torch.testing._internal.opinfo.core import OpInfo @@ -27,20 +25,24 @@ def _test_window(self, device, dtype, op: OpInfo, **kwargs): if op.ref is None: raise unittest.SkipTest("No reference implementation") - sample_inputs = op.sample_inputs(device, dtype, **kwargs) + sample_inputs = op.sample_inputs(device, dtype, False, **kwargs) for sample_input in sample_inputs: window_size = sample_input.input window_name = re.search(self.supported_windows, op.name).group(0) - periodic = sample_input.kwargs.pop('periodic') + + ref_kwargs = { + k: sample_input.kwargs[k] for k in sample_input.kwargs if k not in ('device', 'dtype', 'requires_grad', 'periodic') + } expected = torch.from_numpy( - op.ref((window_name, *(sample_input.kwargs.values())), window_size, fftbins=periodic) + op.ref((window_name, *(ref_kwargs.values())), window_size, fftbins=sample_input.kwargs['periodic']) ) - actual = op(window_size, periodic=periodic, **sample_input.kwargs) + actual = op(window_size, **sample_input.kwargs) self.assertEqual(actual, expected, exact_dtype=self.exact_dtype) - self.assertTrue(op(3, requires_grad=True).requires_grad) - self.assertFalse(op(3).requires_grad) + + self.assertTrue(op(3, requires_grad=True).requires_grad) + self.assertFalse(op(3).requires_grad) def _test_window_errors(self, device, op): error_inputs = op.error_inputs(device) @@ -50,29 +52,15 @@ def _test_window_errors(self, device, op): with self.assertRaisesRegex(error_input.error_type, error_input.error_regex): op(sample_input.input, *sample_input.args, **sample_input.kwargs) - @ops([op for op in signal_funcs if 'windows' in op.name], dtypes=OpDTypes.none) + @ops([op for op in op_db if 'windows' in op.name], dtypes=OpDTypes.none) def test_window_errors(self, device, op): self._test_window_errors(device, op) @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @ops([op for op in signal_funcs if 'windows.cosine' in op.name], - allowed_dtypes=(torch.float, torch.double, torch.long)) - def test_cosine_window(self, device, dtype, op): - self._test_window(device, dtype, op) - - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @ops([op for op in signal_funcs if 'windows.exponential' in op.name], + @ops([op for op in op_db if 'windows' in op.name], allowed_dtypes=(torch.float, torch.double)) - def test_exponential_window(self, device, dtype, op): - for _ in range(50): - self._test_window(device, dtype, op, center=None, tau=random.uniform(0, 10)) - - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @ops([op for op in signal_funcs if 'windows.gaussian' in op.name], - allowed_dtypes=(torch.float, torch.double, torch.long)) - def test_gaussian_window(self, device, dtype, op): - for _ in range(50): - self._test_window(device, dtype, op, std=random.uniform(0, 3)) + def test_windows(self, device, dtype, op): + self._test_window(device, dtype, op) instantiate_device_type_tests(TestSignalWindows, globals()) diff --git a/torch/testing/_internal/opinfo/definitions/__init__.py b/torch/testing/_internal/opinfo/definitions/__init__.py index 14698ec42a612..f718c125730e9 100644 --- a/torch/testing/_internal/opinfo/definitions/__init__.py +++ b/torch/testing/_internal/opinfo/definitions/__init__.py @@ -22,5 +22,4 @@ *fft.python_ref_db, *linalg.python_ref_db, *special.python_ref_db, - *signal.python_ref_db, ] diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index a52e5b5a822bb..98ed75d7bb6c3 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -1,4 +1,7 @@ +import random import unittest + +from itertools import product from typing import List import torch @@ -15,24 +18,39 @@ import scipy.signal -def _sample_input_windows(sample_input, *args, **kwargs): - for size in [0, 1, 2, 5, 10, 50, 100, 1024, 2048]: - for periodic in [True, False]: - kwargs.update( - { - "periodic": periodic, - } - ) - yield sample_input(size, args=args, kwargs=kwargs) +def sample_inputs_window(op_info, device, dtype, requires_grad, *, kws=({},), **kwargs): + _kwargs = dict( + kwargs, **{"device": device, "dtype": dtype, "requires_grad": requires_grad} + ) + sizes = [0, 1, 2, 5, 10, 50, 100, 1024, 2048] + for size, periodic, k in product(sizes, (True, False), kws): + yield SampleInput(size, periodic=periodic, **k, **_kwargs) + + +def sample_inputs_gaussian_window(op_info, device, dtype, requires_grad, **kwargs): + kws = [{"std": random.uniform(0, 3)} for _ in range(50)] + yield from sample_inputs_window( + op_info, device, dtype, requires_grad, kws=kws, **kwargs + ) -def sample_inputs_window(op_info, *args, **kwargs): - return _sample_input_windows(SampleInput, *args, **kwargs) +def sample_inputs_exponential_window(op_info, device, dtype, requires_grad, **kwargs): + kws = [{"center": None, "tau": random.uniform(0, 10)} for _ in range(50)] + yield from sample_inputs_window( + op_info, device, dtype, requires_grad, kws=kws, **kwargs + ) -def error_inputs_window(op_info, *args, **kwargs): +def error_inputs_window(op_info, device, **kwargs): + tmp_kwargs = dict( + kwargs, + **{ + "device": device, + }, + ) + yield ErrorInput( - SampleInput(-1, args=args, kwargs=kwargs), + SampleInput(-1, kwargs=tmp_kwargs), error_type=ValueError, error_regex="requires non-negative window_length, got window_length=-1", ) @@ -45,31 +63,36 @@ def error_inputs_window(op_info, *args, **kwargs): ) yield ErrorInput( - SampleInput(3, args=args, kwargs=tmp_kwargs), + SampleInput(3, kwargs=tmp_kwargs), error_type=ValueError, error_regex="is not implemented for sparse types, got: torch.sparse_coo", ) tmp_kwargs = kwargs - tmp_kwargs["dtype"] = torch.long + tmp_kwargs.update( + { + "dtype": torch.long, + } + ) yield ErrorInput( - SampleInput(3, args=args, kwargs=tmp_kwargs), + SampleInput(3, kwargs=tmp_kwargs), error_type=ValueError, error_regex="expects floating point dtypes, got: torch.int64", ) -def error_inputs_exponential_window(op_info, device, *args, **kwargs): - tmp_kwargs = dict(kwargs, **{"dtype": torch.float32, "device": device}) +def error_inputs_exponential_window(op_info, device, **kwargs): + tmp_kwargs = dict(kwargs, **{"dtype": torch.float32}) + + yield from error_inputs_window(op_info, device, **tmp_kwargs) - for error_input in error_inputs_window(op_info, *args, **kwargs): - yield error_input + tmp_kwargs.update({"device": device}) tmp_kwargs = dict(tmp_kwargs, **{"tau": -1}) yield ErrorInput( - SampleInput(3, args=args, kwargs=tmp_kwargs), + SampleInput(3, kwargs=tmp_kwargs), error_type=ValueError, error_regex="Tau must be positive, got: -1 instead.", ) @@ -77,39 +100,51 @@ def error_inputs_exponential_window(op_info, device, *args, **kwargs): tmp_kwargs = dict(tmp_kwargs, **{"center": 1}) yield ErrorInput( - SampleInput(3, args=args, kwargs=tmp_kwargs), + SampleInput(3, kwargs=tmp_kwargs), error_type=ValueError, error_regex="Center must be 'None' for periodic equal True", ) -def error_inputs_gaussian_window(op_info, device, *args, **kwargs): +def error_inputs_gaussian_window(op_info, device, **kwargs): tmp_kwargs = dict(kwargs, **{"dtype": torch.float32, "device": device}) - for error_input in error_inputs_window(op_info, *args, **kwargs): - yield error_input + yield from error_inputs_window(op_info, device, **kwargs) tmp_kwargs = dict(tmp_kwargs, **{"std": -1}) yield ErrorInput( - SampleInput(3, args=args, kwargs=tmp_kwargs), + SampleInput(3, kwargs=tmp_kwargs), error_type=ValueError, error_regex="Standard deviation must be positive, got: -1 instead.", ) -op_db: List[OpInfo] = [ - OpInfo( - "signal.windows.cosine", +def make_signal_windows_opinfo( + name, variant_test_name, sample_inputs_func, error_inputs_func, *, skips=() +): + return OpInfo( + name=name, + variant_test_name=variant_test_name, ref=scipy.signal.get_window if TEST_SCIPY else None, dtypes=all_types_and(torch.float, torch.double, torch.long), dtypesIfCUDA=all_types_and( torch.float, torch.double, torch.bfloat16, torch.half, torch.long ), - sample_inputs_func=sample_inputs_window, - error_inputs_func=error_inputs_window, + sample_inputs_func=sample_inputs_func, + error_inputs_func=error_inputs_func, supports_out=False, supports_autograd=False, + skips=skips, + ) + + +op_db: List[OpInfo] = [ + make_signal_windows_opinfo( + "signal.windows.cosine", + "signal.windows.cosine_default", + sample_inputs_window, + error_inputs_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -147,17 +182,11 @@ def error_inputs_gaussian_window(op_info, device, *args, **kwargs): DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), ), ), - OpInfo( + make_signal_windows_opinfo( "signal.windows.exponential", - ref=scipy.signal.get_window if TEST_SCIPY else None, - dtypes=all_types_and(torch.float, torch.double, torch.long), - dtypesIfCUDA=all_types_and( - torch.float, torch.double, torch.bfloat16, torch.half, torch.long - ), - sample_inputs_func=sample_inputs_window, - error_inputs_func=error_inputs_exponential_window, - supports_out=False, - supports_autograd=False, + "signal.windows.exponential_default", + sample_inputs_exponential_window, + error_inputs_exponential_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -195,17 +224,11 @@ def error_inputs_gaussian_window(op_info, device, *args, **kwargs): DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), ), ), - OpInfo( + make_signal_windows_opinfo( "signal.windows.gaussian", - ref=scipy.signal.get_window if TEST_SCIPY else None, - dtypes=all_types_and(torch.float, torch.double, torch.long), - dtypesIfCUDA=all_types_and( - torch.float, torch.double, torch.bfloat16, torch.half, torch.long - ), - sample_inputs_func=sample_inputs_window, - error_inputs_func=error_inputs_gaussian_window, - supports_out=False, - supports_autograd=False, + "signal.windows.gaussian_default", + sample_inputs_gaussian_window, + error_inputs_gaussian_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -244,5 +267,3 @@ def error_inputs_gaussian_window(op_info, device, *args, **kwargs): ), ), ] - -python_ref_db: List[OpInfo] = [] From f5e1c45ad5b0cb21839fee8ef2f7dfb51f658595 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:09 -0300 Subject: [PATCH 43/76] Update sqrt and ref kwargs --- test/test_signal.py | 3 ++- torch/signal/windows/windows.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_signal.py b/test/test_signal.py index bc96056f3fe6a..acb12bff1c857 100644 --- a/test/test_signal.py +++ b/test/test_signal.py @@ -32,7 +32,8 @@ def _test_window(self, device, dtype, op: OpInfo, **kwargs): window_name = re.search(self.supported_windows, op.name).group(0) ref_kwargs = { - k: sample_input.kwargs[k] for k in sample_input.kwargs if k not in ('device', 'dtype', 'requires_grad', 'periodic') + k: sample_input.kwargs[k] for k in sample_input.kwargs + if k not in ('device', 'dtype', 'requires_grad', 'periodic') } expected = torch.from_numpy( diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 9613de352688d..7fc48b0782309 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,5 +1,4 @@ import torch -import numpy as np from torch import Tensor from torch._torch_docs import factory_common_args @@ -299,7 +298,7 @@ def gaussian(window_length: int, start = -(window_length if periodic else window_length - 1) / 2.0 - constant = 1 / (std * np.sqrt(2)) + constant = 1 / (std * torch.sqrt(torch.tensor(2)).item()) """ Note that non-integer step is subject to floating point rounding errors when comparing against end; From 66f5bd0a4e517ecb288ffb1d7feb0a6283bfe69a Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:09 -0300 Subject: [PATCH 44/76] Remove unnecesary tests --- test/test_signal.py | 70 --------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 test/test_signal.py diff --git a/test/test_signal.py b/test/test_signal.py deleted file mode 100644 index acb12bff1c857..0000000000000 --- a/test/test_signal.py +++ /dev/null @@ -1,70 +0,0 @@ -# Owner(s): ["module: signal"] - -import torch -import unittest -import re - -from torch.testing._internal.common_utils import ( - TestCase, run_tests -) -from torch.testing._internal.common_device_type import ( - ops, instantiate_device_type_tests, OpDTypes -) -from torch.testing._internal.common_methods_invocations import ( - precisionOverride, op_db -) -from torch.testing._internal.opinfo.core import OpInfo - - -class TestSignalWindows(TestCase): - exact_dtype = False - - supported_windows = 'cosine|exponential|gaussian' - - def _test_window(self, device, dtype, op: OpInfo, **kwargs): - if op.ref is None: - raise unittest.SkipTest("No reference implementation") - - sample_inputs = op.sample_inputs(device, dtype, False, **kwargs) - - for sample_input in sample_inputs: - window_size = sample_input.input - window_name = re.search(self.supported_windows, op.name).group(0) - - ref_kwargs = { - k: sample_input.kwargs[k] for k in sample_input.kwargs - if k not in ('device', 'dtype', 'requires_grad', 'periodic') - } - - expected = torch.from_numpy( - op.ref((window_name, *(ref_kwargs.values())), window_size, fftbins=sample_input.kwargs['periodic']) - ) - actual = op(window_size, **sample_input.kwargs) - self.assertEqual(actual, expected, exact_dtype=self.exact_dtype) - - self.assertTrue(op(3, requires_grad=True).requires_grad) - self.assertFalse(op(3).requires_grad) - - def _test_window_errors(self, device, op): - error_inputs = op.error_inputs(device) - - for error_input in error_inputs: - sample_input = error_input.sample_input - with self.assertRaisesRegex(error_input.error_type, error_input.error_regex): - op(sample_input.input, *sample_input.args, **sample_input.kwargs) - - @ops([op for op in op_db if 'windows' in op.name], dtypes=OpDTypes.none) - def test_window_errors(self, device, op): - self._test_window_errors(device, op) - - @precisionOverride({torch.bfloat16: 5e-2, torch.half: 1e-3}) - @ops([op for op in op_db if 'windows' in op.name], - allowed_dtypes=(torch.float, torch.double)) - def test_windows(self, device, dtype, op): - self._test_window(device, dtype, op) - - -instantiate_device_type_tests(TestSignalWindows, globals()) - -if __name__ == '__main__': - run_tests() From 75b8010124790901fc3eaa2267f7448168b961c1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:10 -0300 Subject: [PATCH 45/76] Address comments --- torch/signal/windows/windows.py | 103 +++++------ .../_internal/opinfo/definitions/signal.py | 162 +++++++++--------- 2 files changed, 129 insertions(+), 136 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 7fc48b0782309..99f4c398b7ac7 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,6 +1,8 @@ import torch +import numpy as np from torch import Tensor +from torch._prims_common import is_float_dtype, is_complex_dtype from torch._torch_docs import factory_common_args from torch.types import _dtype, _device, _layout @@ -40,18 +42,11 @@ def _window_function_checks(function_name: str, window_length: int, dtype: _dtyp dtype (:class:`torch.dtype`): the desired data type of the window tensor. layout (:class:`torch.layout`): the desired layout of the window tensor. """ - - def is_floating_type(t: _dtype) -> bool: - return t == torch.float32 or t == torch.bfloat16 or t == torch.float64 or t == torch.float16 - - def is_complex_type(t: _dtype) -> bool: - return t == torch.complex64 or t == torch.complex128 or t == torch.complex32 - if window_length < 0: raise ValueError(f'{function_name} requires non-negative window_length, got window_length={window_length}') if layout is not torch.strided: - raise ValueError(f'{function_name} is not implemented for sparse types, got: {layout}') - if not is_floating_type(dtype) and not is_complex_type(dtype): + raise ValueError(f'{function_name} is implemented for strided tensors only, got: {layout}') + if not is_float_dtype(dtype): raise ValueError(f'{function_name} expects floating point dtypes, got: {dtype}') @@ -68,22 +63,22 @@ def is_complex_type(t: _dtype) -> bool: r""" Args: - window_length (int): the length of the output window. - In other words, the number of points of the ee window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. - center (float, optional): his value defines where the center of the window will be located. + M (int): the length of the output window. + In other words, the number of points of the exponential window. + center (float, optional): where the center of the window will be located. In other words, at which sample the peak of the window can be found. Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. tau (float, optional): the decay value. For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, if `x` is the fraction of the window remaining at the end. Default: 1.0. + sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. + If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. """ + r""" .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. + and `sym` is `True`. Keyword args: {dtype} @@ -105,34 +100,27 @@ def is_complex_type(t: _dtype) -> bool: **factory_common_args ), ) -def exponential(window_length: int, - periodic: bool = True, - center: float = None, - tau: float = 1.0, - *, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, - requires_grad: bool = False) -> Tensor: +def exponential(M: int, center: float = None, tau: float = 1.0, sym: bool = True, *, dtype: _dtype = None, + layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('exponential', window_length, dtype, layout) + _window_function_checks('exponential', M, dtype, layout) - if window_length == 0: + if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if window_length == 1: + if M == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if periodic and center is not None: - raise ValueError('Center must be \'None\' for periodic equal True') - if tau <= 0: raise ValueError(f'Tau must be positive, got: {tau} instead.') + if not sym and center is not None: + raise ValueError('Center must be \'None\' for non-symmetric windows') + if center is None: - center = -(window_length if periodic else window_length - 1) / 2.0 + center = -(M if not sym else M - 1) / 2.0 constant = 1 / tau @@ -141,7 +129,7 @@ def exponential(window_length: int, thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ k = torch.arange(start=center * constant, - end=(center + (window_length - 1)) * constant + constant / 2, + end=(center + (M - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, @@ -166,14 +154,14 @@ def exponential(window_length: int, r""" Args: - window_length (int): the length of the output window. + M (int): the length of the output window. In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True`. + sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. + If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. + and `sym` is `True`. Keyword args: {dtype} @@ -195,8 +183,8 @@ def exponential(window_length: int, **factory_common_args ), ) -def cosine(window_length: int, - periodic: bool = True, +def cosine(M: int, + sym: bool = True, *, dtype: _dtype = None, layout: _layout = torch.strided, @@ -205,23 +193,23 @@ def cosine(window_length: int, if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('cosine', window_length, dtype, layout) + _window_function_checks('cosine', M, dtype, layout) - if window_length == 0: + if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if window_length == 1: + if M == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) start = 0.5 - constant = torch.pi / (window_length + 1 if periodic else window_length) + constant = torch.pi / (M + 1 if not sym else M) """ Note that non-integer step is subject to floating point rounding errors when comparing against end; thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ k = torch.arange(start=start * constant, - end=(start + (window_length - 1)) * constant + constant / 2, + end=(start + (M - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, @@ -243,16 +231,15 @@ def cosine(window_length: int, r""" Args: - window_length (int): the length of the output window. + M (int): the length of the output window. In other words, the number of points of the cosine window. - periodic (bool, optional): If `True`, returns a periodic window suitable for use in spectral analysis. - If `False`, returns a symmetric window suitable for use in filter design. Default: `True` - std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. - Default: 0.5. + std (float): the standard deviation of the gaussian. It controls how narrow or wide the window is. + sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. + If `True`, returns a symmetric window suitable for use in filter design. Default: `True` .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `periodic` is `False`. + and `sym` is `True`. Keyword args: {dtype} @@ -274,9 +261,9 @@ def cosine(window_length: int, **factory_common_args ), ) -def gaussian(window_length: int, - periodic: bool = True, - std: float = 1., +def gaussian(M: int, + std: float, + sym: bool = True, *, dtype: _dtype = None, layout: _layout = torch.strided, @@ -285,27 +272,27 @@ def gaussian(window_length: int, if dtype is None: dtype = torch.get_default_dtype() - _window_function_checks('gaussian', window_length, dtype, layout) + _window_function_checks('gaussian', M, dtype, layout) - if window_length == 0: + if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if window_length == 1: + if M == 1: return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) if std <= 0: raise ValueError(f'Standard deviation must be positive, got: {std} instead.') - start = -(window_length if periodic else window_length - 1) / 2.0 + start = -(M if not sym else M - 1) / 2.0 - constant = 1 / (std * torch.sqrt(torch.tensor(2)).item()) + constant = 1 / (std * np.sqrt(2)) """ Note that non-integer step is subject to floating point rounding errors when comparing against end; thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ k = torch.arange(start=start * constant, - end=(start + (window_length - 1)) * constant + constant / 2, + end=(start + (M - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 98ed75d7bb6c3..b23a80afdd424 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -1,5 +1,6 @@ import random import unittest +from functools import partial from itertools import product from typing import List @@ -13,124 +14,126 @@ OpInfo, SampleInput, ) +from torch.testing._legacy import floating_types_and, floating_types if TEST_SCIPY: import scipy.signal -def sample_inputs_window(op_info, device, dtype, requires_grad, *, kws=({},), **kwargs): - _kwargs = dict( - kwargs, **{"device": device, "dtype": dtype, "requires_grad": requires_grad} - ) - sizes = [0, 1, 2, 5, 10, 50, 100, 1024, 2048] - for size, periodic, k in product(sizes, (True, False), kws): - yield SampleInput(size, periodic=periodic, **k, **_kwargs) +def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs): + r"""Base function used to create sample inputs for windows. + + For additional required args you should use *args, as well as **kwargs for + additional keyword arguments. + """ + + # Test a window size of length zero and one. + # If it's either symmetric or not doesn't matter in these sample inputs. + for size in [0, 1]: + yield SampleInput( + size, + *args, + device=device, + dtype=dtype, + requires_grad=requires_grad, + **kwargs + ) + + # For sizes larger than 1 we need to test both symmetric and non-symmetric windows. + # Note: sample input tensors must be kept rather small. + sizes = [2, 5, 10, 50] + for size, sym in product(sizes, (True, False)): + yield SampleInput( + size, + *args, + sym=sym, + device=device, + dtype=dtype, + requires_grad=requires_grad, + **kwargs + ) def sample_inputs_gaussian_window(op_info, device, dtype, requires_grad, **kwargs): - kws = [{"std": random.uniform(0, 3)} for _ in range(50)] - yield from sample_inputs_window( - op_info, device, dtype, requires_grad, kws=kws, **kwargs - ) - - -def sample_inputs_exponential_window(op_info, device, dtype, requires_grad, **kwargs): - kws = [{"center": None, "tau": random.uniform(0, 10)} for _ in range(50)] yield from sample_inputs_window( - op_info, device, dtype, requires_grad, kws=kws, **kwargs + op_info, + device, + dtype, + requires_grad, + random.uniform(0, 3), # std, + **kwargs ) -def error_inputs_window(op_info, device, **kwargs): - tmp_kwargs = dict( - kwargs, - **{ - "device": device, - }, - ) - +def error_inputs_window(op_info, device, *args, **kwargs): + # Tests for windows that have a negative size yield ErrorInput( - SampleInput(-1, kwargs=tmp_kwargs), + SampleInput(-1, *args, dtype=torch.float32, device=device, **kwargs), error_type=ValueError, error_regex="requires non-negative window_length, got window_length=-1", ) - tmp_kwargs = dict( - kwargs, - **{ - "layout": torch.sparse_coo, - }, - ) - + # Tests for window tensors that are not torch.strided, for instance, torch.sparse_coo. yield ErrorInput( - SampleInput(3, kwargs=tmp_kwargs), + SampleInput(3, *args, layout=torch.sparse_coo, device=device, dtype=torch.float32, **kwargs), error_type=ValueError, - error_regex="is not implemented for sparse types, got: torch.sparse_coo", - ) - - tmp_kwargs = kwargs - tmp_kwargs.update( - { - "dtype": torch.long, - } + error_regex="is implemented for strided tensors only, got: torch.sparse_coo", ) + # Tests for window tensors that are not floating point dtypes, for instance, torch.long. yield ErrorInput( - SampleInput(3, kwargs=tmp_kwargs), + SampleInput(3, *args, dtype=torch.long, device=device, **kwargs), error_type=ValueError, error_regex="expects floating point dtypes, got: torch.int64", ) def error_inputs_exponential_window(op_info, device, **kwargs): - tmp_kwargs = dict(kwargs, **{"dtype": torch.float32}) - - yield from error_inputs_window(op_info, device, **tmp_kwargs) - - tmp_kwargs.update({"device": device}) - - tmp_kwargs = dict(tmp_kwargs, **{"tau": -1}) + # Yield common error inputs + yield from error_inputs_window(op_info, device, 0.5, **kwargs) + # Tests for negative decay values. yield ErrorInput( - SampleInput(3, kwargs=tmp_kwargs), + SampleInput(3, tau=-1, dtype=torch.float32, device=device, **kwargs), error_type=ValueError, error_regex="Tau must be positive, got: -1 instead.", ) - tmp_kwargs = dict(tmp_kwargs, **{"center": 1}) - + # Tests for non-symmetric windows and a given center value. yield ErrorInput( - SampleInput(3, kwargs=tmp_kwargs), + SampleInput(3, center=1, sym=False, dtype=torch.float32, device=device), error_type=ValueError, - error_regex="Center must be 'None' for periodic equal True", + error_regex="Center must be 'None' for non-symmetric windows", ) def error_inputs_gaussian_window(op_info, device, **kwargs): - tmp_kwargs = dict(kwargs, **{"dtype": torch.float32, "device": device}) - - yield from error_inputs_window(op_info, device, **kwargs) - - tmp_kwargs = dict(tmp_kwargs, **{"std": -1}) + # Yield common error inputs + yield from error_inputs_window( + op_info, + device, + 0.5, # std + **kwargs + ) + # Tests for negative standard deviations yield ErrorInput( - SampleInput(3, kwargs=tmp_kwargs), + SampleInput(3, -1, dtype=torch.float32, device=device, **kwargs), error_type=ValueError, error_regex="Standard deviation must be positive, got: -1 instead.", ) def make_signal_windows_opinfo( - name, variant_test_name, sample_inputs_func, error_inputs_func, *, skips=() + name, variant_test_name, ref, sample_inputs_func, error_inputs_func, *, skips=() ): + r"""Helper function to create OpInfo objects related to different windows.""" return OpInfo( name=name, variant_test_name=variant_test_name, - ref=scipy.signal.get_window if TEST_SCIPY else None, - dtypes=all_types_and(torch.float, torch.double, torch.long), - dtypesIfCUDA=all_types_and( - torch.float, torch.double, torch.bfloat16, torch.half, torch.long - ), + ref=ref if TEST_SCIPY else None, + dtypes=floating_types_and(torch.bfloat16, torch.float16), + dtypesIfCUDA=floating_types_and(torch.bfloat16, torch.float16), sample_inputs_func=sample_inputs_func, error_inputs_func=error_inputs_func, supports_out=False, @@ -141,10 +144,11 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( - "signal.windows.cosine", - "signal.windows.cosine_default", - sample_inputs_window, - error_inputs_window, + name="signal.windows.cosine", + variant_test_name="signal.windows.cosine_default", + ref=scipy.signal.windows.cosine, + sample_inputs_func=sample_inputs_window, + error_inputs_func=error_inputs_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -183,10 +187,11 @@ def make_signal_windows_opinfo( ), ), make_signal_windows_opinfo( - "signal.windows.exponential", - "signal.windows.exponential_default", - sample_inputs_exponential_window, - error_inputs_exponential_window, + name="signal.windows.exponential", + variant_test_name="signal.windows.exponential_default", + ref=scipy.signal.windows.exponential, + sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), + error_inputs_func=error_inputs_exponential_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -225,10 +230,11 @@ def make_signal_windows_opinfo( ), ), make_signal_windows_opinfo( - "signal.windows.gaussian", - "signal.windows.gaussian_default", - sample_inputs_gaussian_window, - error_inputs_gaussian_window, + name="signal.windows.gaussian", + variant_test_name="signal.windows.gaussian_default", + ref=scipy.signal.windows.gaussian, + sample_inputs_func=sample_inputs_gaussian_window, + error_inputs_func=error_inputs_gaussian_window, skips=( DecorateInfo( unittest.expectedFailure, From 359e62be12033df6c3c6003681be83add186591f Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:10 -0300 Subject: [PATCH 46/76] Solve lint issues --- torch/signal/windows/windows.py | 2 +- .../_internal/opinfo/definitions/signal.py | 32 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 99f4c398b7ac7..95012d9b0965c 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -2,7 +2,7 @@ import numpy as np from torch import Tensor -from torch._prims_common import is_float_dtype, is_complex_dtype +from torch._prims_common import is_float_dtype from torch._torch_docs import factory_common_args from torch.types import _dtype, _device, _layout diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index b23a80afdd424..83ee8d1ee162a 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -6,7 +6,6 @@ from typing import List import torch -from torch.testing._internal.common_dtype import all_types_and from torch.testing._internal.common_utils import TEST_SCIPY from torch.testing._internal.opinfo.core import ( DecorateInfo, @@ -14,7 +13,7 @@ OpInfo, SampleInput, ) -from torch.testing._legacy import floating_types_and, floating_types +from torch.testing._legacy import floating_types_and if TEST_SCIPY: import scipy.signal @@ -36,7 +35,7 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) device=device, dtype=dtype, requires_grad=requires_grad, - **kwargs + **kwargs, ) # For sizes larger than 1 we need to test both symmetric and non-symmetric windows. @@ -50,18 +49,13 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) device=device, dtype=dtype, requires_grad=requires_grad, - **kwargs + **kwargs, ) def sample_inputs_gaussian_window(op_info, device, dtype, requires_grad, **kwargs): yield from sample_inputs_window( - op_info, - device, - dtype, - requires_grad, - random.uniform(0, 3), # std, - **kwargs + op_info, device, dtype, requires_grad, random.uniform(0, 3), **kwargs # std, ) @@ -75,7 +69,14 @@ def error_inputs_window(op_info, device, *args, **kwargs): # Tests for window tensors that are not torch.strided, for instance, torch.sparse_coo. yield ErrorInput( - SampleInput(3, *args, layout=torch.sparse_coo, device=device, dtype=torch.float32, **kwargs), + SampleInput( + 3, + *args, + layout=torch.sparse_coo, + device=device, + dtype=torch.float32, + **kwargs, + ), error_type=ValueError, error_regex="is implemented for strided tensors only, got: torch.sparse_coo", ) @@ -109,12 +110,7 @@ def error_inputs_exponential_window(op_info, device, **kwargs): def error_inputs_gaussian_window(op_info, device, **kwargs): # Yield common error inputs - yield from error_inputs_window( - op_info, - device, - 0.5, # std - **kwargs - ) + yield from error_inputs_window(op_info, device, 0.5, **kwargs) # std # Tests for negative standard deviations yield ErrorInput( @@ -125,7 +121,7 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): def make_signal_windows_opinfo( - name, variant_test_name, ref, sample_inputs_func, error_inputs_func, *, skips=() + name, variant_test_name, ref, sample_inputs_func, error_inputs_func, *, skips=() ): r"""Helper function to create OpInfo objects related to different windows.""" return OpInfo( From 7aa10c4bede0c3fc4596521b129b9d438b6744dc Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:10 -0300 Subject: [PATCH 47/76] Update signal.py --- torch/testing/_internal/opinfo/definitions/signal.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 83ee8d1ee162a..dc11b6dffad36 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -141,7 +141,7 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( name="signal.windows.cosine", - variant_test_name="signal.windows.cosine_default", + variant_test_name="", ref=scipy.signal.windows.cosine, sample_inputs_func=sample_inputs_window, error_inputs_func=error_inputs_window, @@ -178,13 +178,11 @@ def make_signal_windows_opinfo( unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" ), DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), - # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. - DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), ), ), make_signal_windows_opinfo( name="signal.windows.exponential", - variant_test_name="signal.windows.exponential_default", + variant_test_name="", ref=scipy.signal.windows.exponential, sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), error_inputs_func=error_inputs_exponential_window, @@ -221,13 +219,11 @@ def make_signal_windows_opinfo( unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" ), DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), - # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. - DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), ), ), make_signal_windows_opinfo( name="signal.windows.gaussian", - variant_test_name="signal.windows.gaussian_default", + variant_test_name="", ref=scipy.signal.windows.gaussian, sample_inputs_func=sample_inputs_gaussian_window, error_inputs_func=error_inputs_gaussian_window, @@ -264,8 +260,6 @@ def make_signal_windows_opinfo( unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" ), DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), - # UserWarning not triggered : Resized a non-empty tensor but did not warn about it. - DecorateInfo(unittest.expectedFailure, "TestCommon", "test_out_warning"), ), ), ] From bb198a28eea4b9d1dba6a6338dddc43d1ea5d60e Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:11 -0300 Subject: [PATCH 48/76] Update tests --- torch/signal/windows/windows.py | 43 +++--- torch/testing/_internal/common_utils.py | 6 + .../_internal/opinfo/definitions/signal.py | 123 ++++-------------- 3 files changed, 58 insertions(+), 114 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 95012d9b0965c..d447f9f3550ee 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -4,7 +4,6 @@ from torch import Tensor from torch._prims_common import is_float_dtype from torch._torch_docs import factory_common_args -from torch.types import _dtype, _device, _layout __all__ = [ 'cosine', @@ -32,18 +31,18 @@ def decorator(o): return decorator -def _window_function_checks(function_name: str, window_length: int, dtype: _dtype, layout: _layout) -> None: +def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layout: torch.layout) -> None: r"""Performs common checks for all the defined windows. This function should be called before computing any window Args: function_name (str): name of the window function. - window_length (int): length of the window. + M (int): length of the window. dtype (:class:`torch.dtype`): the desired data type of the window tensor. layout (:class:`torch.layout`): the desired layout of the window tensor. """ - if window_length < 0: - raise ValueError(f'{function_name} requires non-negative window_length, got window_length={window_length}') + if M < 0: + raise ValueError(f'{function_name} requires non-negative window_length, got window_length={M}') if layout is not torch.strided: raise ValueError(f'{function_name} is implemented for strided tensors only, got: {layout}') if not is_float_dtype(dtype): @@ -68,9 +67,7 @@ def _window_function_checks(function_name: str, window_length: int, dtype: _dtyp center (float, optional): where the center of the window will be located. In other words, at which sample the peak of the window can be found. Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. - tau (float, optional): the decay value. - For `center = 0`, it's suggested to use :math:`\tau = -\frac{(M - 1)}{\ln(x)}`, - if `x` is the fraction of the window remaining at the end. Default: 1.0. + tau (float, optional): the decay value. Default: 1.0. sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. """ + @@ -100,8 +97,17 @@ def _window_function_checks(function_name: str, window_length: int, dtype: _dtyp **factory_common_args ), ) -def exponential(M: int, center: float = None, tau: float = 1.0, sym: bool = True, *, dtype: _dtype = None, - layout: _layout = torch.strided, device: _device = None, requires_grad: bool = False) -> Tensor: +def exponential( + M: int, + center: float = None, + tau: float = 1.0, + sym: bool = True, + *, + dtype: torch.dtype = None, + layout: torch.layout = torch.strided, + device: torch.device = None, + requires_grad: bool = False +) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() @@ -186,9 +192,9 @@ def exponential(M: int, center: float = None, tau: float = 1.0, sym: bool = True def cosine(M: int, sym: bool = True, *, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, + dtype: torch.dtype = None, + layout: torch.layout = torch.strided, + device: torch.device = None, requires_grad: bool = False) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() @@ -233,7 +239,8 @@ def cosine(M: int, Args: M (int): the length of the output window. In other words, the number of points of the cosine window. - std (float): the standard deviation of the gaussian. It controls how narrow or wide the window is. + std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. + Default: 1.0. sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. If `True`, returns a symmetric window suitable for use in filter design. Default: `True` @@ -262,12 +269,12 @@ def cosine(M: int, ), ) def gaussian(M: int, - std: float, + std: float = 1.0, sym: bool = True, *, - dtype: _dtype = None, - layout: _layout = torch.strided, - device: _device = None, + dtype: torch.dtype = None, + layout: torch.layout = torch.strided, + device: torch.device = None, requires_grad: bool = False) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() diff --git a/torch/testing/_internal/common_utils.py b/torch/testing/_internal/common_utils.py index d60cffbb53dc6..48d8859bd5ca8 100644 --- a/torch/testing/_internal/common_utils.py +++ b/torch/testing/_internal/common_utils.py @@ -2341,6 +2341,12 @@ def safeToDense(self, t): def compare_with_reference(self, torch_fn, ref_fn, sample_input, **kwargs): numpy_sample = sample_input.numpy() n_inp, n_args, n_kwargs = numpy_sample.input, numpy_sample.args, numpy_sample.kwargs + + # Remove torch-specific kwargs + for torch_key in {'device', 'layout', 'dtype', 'requires_grad'}: + if torch_key in n_kwargs: + n_kwargs.pop(torch_key) + t_inp, t_args, t_kwargs = sample_input.input, sample_input.args, sample_input.kwargs actual = torch_fn(t_inp, *t_args, **t_kwargs) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index dc11b6dffad36..dd581095e4d70 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -28,7 +28,7 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) # Test a window size of length zero and one. # If it's either symmetric or not doesn't matter in these sample inputs. - for size in [0, 1]: + for size in range(2): yield SampleInput( size, *args, @@ -40,8 +40,7 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) # For sizes larger than 1 we need to test both symmetric and non-symmetric windows. # Note: sample input tensors must be kept rather small. - sizes = [2, 5, 10, 50] - for size, sym in product(sizes, (True, False)): + for size, sym in product(list(range(2, 6)), (True, False)): yield SampleInput( size, *args, @@ -53,12 +52,6 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) ) -def sample_inputs_gaussian_window(op_info, device, dtype, requires_grad, **kwargs): - yield from sample_inputs_window( - op_info, device, dtype, requires_grad, random.uniform(0, 3), **kwargs # std, - ) - - def error_inputs_window(op_info, device, *args, **kwargs): # Tests for windows that have a negative size yield ErrorInput( @@ -91,7 +84,7 @@ def error_inputs_window(op_info, device, *args, **kwargs): def error_inputs_exponential_window(op_info, device, **kwargs): # Yield common error inputs - yield from error_inputs_window(op_info, device, 0.5, **kwargs) + yield from error_inputs_window(op_info, device, **kwargs) # Tests for negative decay values. yield ErrorInput( @@ -110,23 +103,22 @@ def error_inputs_exponential_window(op_info, device, **kwargs): def error_inputs_gaussian_window(op_info, device, **kwargs): # Yield common error inputs - yield from error_inputs_window(op_info, device, 0.5, **kwargs) # std + yield from error_inputs_window(op_info, device, std=0.5, **kwargs) # Tests for negative standard deviations yield ErrorInput( - SampleInput(3, -1, dtype=torch.float32, device=device, **kwargs), + SampleInput(3, std=-1, dtype=torch.float32, device=device, **kwargs), error_type=ValueError, error_regex="Standard deviation must be positive, got: -1 instead.", ) def make_signal_windows_opinfo( - name, variant_test_name, ref, sample_inputs_func, error_inputs_func, *, skips=() + name, ref, sample_inputs_func, error_inputs_func, *, skips=() ): r"""Helper function to create OpInfo objects related to different windows.""" return OpInfo( name=name, - variant_test_name=variant_test_name, ref=ref if TEST_SCIPY else None, dtypes=floating_types_and(torch.bfloat16, torch.float16), dtypesIfCUDA=floating_types_and(torch.bfloat16, torch.float16), @@ -134,17 +126,6 @@ def make_signal_windows_opinfo( error_inputs_func=error_inputs_func, supports_out=False, supports_autograd=False, - skips=skips, - ) - - -op_db: List[OpInfo] = [ - make_signal_windows_opinfo( - name="signal.windows.cosine", - variant_test_name="", - ref=scipy.signal.windows.cosine, - sample_inputs_func=sample_inputs_window, - error_inputs_func=error_inputs_window, skips=( DecorateInfo( unittest.expectedFailure, @@ -178,88 +159,38 @@ def make_signal_windows_opinfo( unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" ), DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), + DecorateInfo( + unittest.skip("Skipped!"), + "TestVmapOperatorsOpInfo", + "test_vmap_exhaustive", + ), + DecorateInfo( + unittest.skip("Skipped!"), + "TestVmapOperatorsOpInfo", + "test_op_has_batch_rule", + ), + *skips, ), + ) + + +op_db: List[OpInfo] = [ + make_signal_windows_opinfo( + name="signal.windows.cosine", + ref=scipy.signal.windows.cosine, + sample_inputs_func=sample_inputs_window, + error_inputs_func=error_inputs_window, ), make_signal_windows_opinfo( name="signal.windows.exponential", - variant_test_name="", ref=scipy.signal.windows.exponential, sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), error_inputs_func=error_inputs_exponential_window, - skips=( - DecorateInfo( - unittest.expectedFailure, - "TestNormalizeOperators", - "test_normalize_operator_exhaustive", - ), - # TODO: same as this? - # https://github.com/pytorch/pytorch/issues/81774 - # also see: arange, new_full - # fails to match any schemas despite working in the interpreter - DecorateInfo( - unittest.expectedFailure, - "TestOperatorSignatures", - "test_get_torch_func_signature_exhaustive", - ), - # fails to match any schemas despite working in the interpreter - DecorateInfo( - unittest.expectedFailure, "TestJit", "test_variant_consistency_jit" - ), - # skip these tests since we have non tensor input - DecorateInfo( - unittest.skip("Skipped!"), "TestCommon", "test_noncontiguous_samples" - ), - DecorateInfo( - unittest.skip("Skipped!"), - "TestCommon", - "test_variant_consistency_eager", - ), - DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_conj_view"), - DecorateInfo( - unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" - ), - DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), - ), ), make_signal_windows_opinfo( name="signal.windows.gaussian", - variant_test_name="", ref=scipy.signal.windows.gaussian, - sample_inputs_func=sample_inputs_gaussian_window, + sample_inputs_func=partial(sample_inputs_window, std=random.uniform(0, 3)), error_inputs_func=error_inputs_gaussian_window, - skips=( - DecorateInfo( - unittest.expectedFailure, - "TestNormalizeOperators", - "test_normalize_operator_exhaustive", - ), - # TODO: same as this? - # https://github.com/pytorch/pytorch/issues/81774 - # also see: arange, new_full - # fails to match any schemas despite working in the interpreter - DecorateInfo( - unittest.expectedFailure, - "TestOperatorSignatures", - "test_get_torch_func_signature_exhaustive", - ), - # fails to match any schemas despite working in the interpreter - DecorateInfo( - unittest.expectedFailure, "TestJit", "test_variant_consistency_jit" - ), - # skip these tests since we have non tensor input - DecorateInfo( - unittest.skip("Skipped!"), "TestCommon", "test_noncontiguous_samples" - ), - DecorateInfo( - unittest.skip("Skipped!"), - "TestCommon", - "test_variant_consistency_eager", - ), - DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_conj_view"), - DecorateInfo( - unittest.skip("Skipped!"), "TestMathBits", "test_neg_conj_view" - ), - DecorateInfo(unittest.skip("Skipped!"), "TestMathBits", "test_neg_view"), - ), ), ] From 93ab7559e3bcf0ae5c2455874aa6bde07991f244 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:11 -0300 Subject: [PATCH 49/76] Update tests --- torch/testing/_internal/opinfo/definitions/signal.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index dd581095e4d70..6ebfee6d7bc4b 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -127,11 +127,6 @@ def make_signal_windows_opinfo( supports_out=False, supports_autograd=False, skips=( - DecorateInfo( - unittest.expectedFailure, - "TestNormalizeOperators", - "test_normalize_operator_exhaustive", - ), # TODO: same as this? # https://github.com/pytorch/pytorch/issues/81774 # also see: arange, new_full From 6cd259298f42e3633c55ac768629a884f4f4be32 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:12 -0300 Subject: [PATCH 50/76] Add make reference --- torch/testing/_internal/common_utils.py | 6 ----- .../_internal/opinfo/definitions/signal.py | 22 ++++++++++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/torch/testing/_internal/common_utils.py b/torch/testing/_internal/common_utils.py index 48d8859bd5ca8..d60cffbb53dc6 100644 --- a/torch/testing/_internal/common_utils.py +++ b/torch/testing/_internal/common_utils.py @@ -2341,12 +2341,6 @@ def safeToDense(self, t): def compare_with_reference(self, torch_fn, ref_fn, sample_input, **kwargs): numpy_sample = sample_input.numpy() n_inp, n_args, n_kwargs = numpy_sample.input, numpy_sample.args, numpy_sample.kwargs - - # Remove torch-specific kwargs - for torch_key in {'device', 'layout', 'dtype', 'requires_grad'}: - if torch_key in n_kwargs: - n_kwargs.pop(torch_key) - t_inp, t_args, t_kwargs = sample_input.input, sample_input.args, sample_input.kwargs actual = torch_fn(t_inp, *t_args, **t_kwargs) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 6ebfee6d7bc4b..8abf5249d4942 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -113,6 +113,22 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): ) +def make_signal_windows_ref(fn): + r"""Wrapper for signal window references. + + Particularly used for window references that don't have a matching signature with + torch, e.g., gaussian window. + """ + def _fn(*args, **kwargs): + # Remove torch-specific kwargs + for torch_key in {'device', 'layout', 'dtype', 'requires_grad'}: + if torch_key in kwargs: + kwargs.pop(torch_key) + return fn(*args, **kwargs) + + return _fn + + def make_signal_windows_opinfo( name, ref, sample_inputs_func, error_inputs_func, *, skips=() ): @@ -172,19 +188,19 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( name="signal.windows.cosine", - ref=scipy.signal.windows.cosine, + ref=make_signal_windows_ref(scipy.signal.windows.cosine), sample_inputs_func=sample_inputs_window, error_inputs_func=error_inputs_window, ), make_signal_windows_opinfo( name="signal.windows.exponential", - ref=scipy.signal.windows.exponential, + ref=make_signal_windows_ref(scipy.signal.windows.exponential), sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), error_inputs_func=error_inputs_exponential_window, ), make_signal_windows_opinfo( name="signal.windows.gaussian", - ref=scipy.signal.windows.gaussian, + ref=make_signal_windows_ref(scipy.signal.windows.gaussian), sample_inputs_func=partial(sample_inputs_window, std=random.uniform(0, 3)), error_inputs_func=error_inputs_gaussian_window, ), From 5bb92437ff784eca4a2fd03ddaba107983c032b1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:12 -0300 Subject: [PATCH 51/76] Update docstrings and errors --- torch/signal/windows/windows.py | 4 ++-- torch/testing/_internal/opinfo/definitions/signal.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index d447f9f3550ee..9e7f82afd75b2 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -42,7 +42,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo layout (:class:`torch.layout`): the desired layout of the window tensor. """ if M < 0: - raise ValueError(f'{function_name} requires non-negative window_length, got window_length={M}') + raise ValueError(f'{function_name} requires non-negative window length, got M={M}') if layout is not torch.strided: raise ValueError(f'{function_name} is implemented for strided tensors only, got: {layout}') if not is_float_dtype(dtype): @@ -66,7 +66,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo In other words, the number of points of the exponential window. center (float, optional): where the center of the window will be located. In other words, at which sample the peak of the window can be found. - Default: `window_length / 2` if `periodic` is `True` (default), else `(window_length - 1) / 2`. + Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. tau (float, optional): the decay value. Default: 1.0. sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 8abf5249d4942..309eba9f95de9 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -57,7 +57,7 @@ def error_inputs_window(op_info, device, *args, **kwargs): yield ErrorInput( SampleInput(-1, *args, dtype=torch.float32, device=device, **kwargs), error_type=ValueError, - error_regex="requires non-negative window_length, got window_length=-1", + error_regex="requires non-negative window length, got M=-1", ) # Tests for window tensors that are not torch.strided, for instance, torch.sparse_coo. From e08461cf879efaa336a07ef38033abf0af907c99 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:13 -0300 Subject: [PATCH 52/76] Correct docstrings --- torch/signal/windows/windows.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 9e7f82afd75b2..16639d997c676 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -89,8 +89,8 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, 0.0183]) - >>> # Generate a symmetric exponential window and decay factor equal to .5 - >>> torch.signal.windows.exponential(10,periodic=False,tau=.5) + >>> # Generate a periodic exponential window and decay factor equal to .5 + >>> torch.signal.windows.exponential(10,sym=False,tau=.5) tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) """.format( @@ -182,7 +182,7 @@ def exponential( 0.4154]) >>> # Generate a symmetric cosine window. - >>> torch.signal.windows.cosine(10,periodic=False) + >>> torch.signal.windows.cosine(10,sym=False) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) """.format( @@ -260,8 +260,8 @@ def cosine(M: int, tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) - >>> # Generate a symmetric gaussian window and standard deviation equal to 0.9. - >>> torch.signal.windows.gaussian(10,periodic=False,std=0.9) + >>> # Generate a periodic gaussian window and standard deviation equal to 0.9. + >>> torch.signal.windows.gaussian(10,sym=False,std=0.9) tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) """.format( From f5642933ef8b2e2d63765e9af9653fb9d05c664c Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:13 -0300 Subject: [PATCH 53/76] Update examples --- torch/signal/windows/windows.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 16639d997c676..e0c8d25d19298 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -86,13 +86,13 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo Examples: >>> # Generate an exponential window without keyword args. >>> torch.signal.windows.exponential(10) - tensor([0.0067, 0.0183, 0.0498, 0.1353, 0.3679, 1.0000, 0.3679, 0.1353, 0.0498, - 0.0183]) + tensor([0.0111, 0.0302, 0.0821, 0.2231, 0.6065, 0.6065, 0.2231, 0.0821, 0.0302, + 0.0111]) >>> # Generate a periodic exponential window and decay factor equal to .5 >>> torch.signal.windows.exponential(10,sym=False,tau=.5) - tensor([1.2341e-04, 9.1188e-04, 6.7379e-03, 4.9787e-02, 3.6788e-01, 3.6788e-01, - 4.9787e-02, 6.7379e-03, 9.1188e-04, 1.2341e-04]) + tensor([4.5400e-05, 3.3546e-04, 2.4788e-03, 1.8316e-02, 1.3534e-01, 1.0000e+00, + 1.3534e-01, 1.8316e-02, 2.4788e-03, 3.3546e-04]) """.format( **factory_common_args ), @@ -178,13 +178,13 @@ def exponential( Examples: >>> # Generate a cosine window without keyword args. >>> torch.signal.windows.cosine(10) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, + 0.1564]) - >>> # Generate a symmetric cosine window. + >>> # Generate a periodic cosine window. >>> torch.signal.windows.cosine(10,sym=False) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, + 0.4154]) """.format( **factory_common_args ), @@ -257,13 +257,13 @@ def cosine(M: int, Examples: >>> # Generate a gaussian window without keyword args. >>> torch.signal.windows.gaussian(10) - tensor([1.9287e-22, 1.2664e-14, 1.5230e-08, 3.3546e-04, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 3.3546e-04, 1.5230e-08, 1.2664e-14]) + tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, + 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) >>> # Generate a periodic gaussian window and standard deviation equal to 0.9. >>> torch.signal.windows.gaussian(10,sym=False,std=0.9) - tensor([3.7267e-06, 5.1998e-04, 2.1110e-02, 2.4935e-01, 8.5700e-01, 8.5700e-01, - 2.4935e-01, 2.1110e-02, 5.1998e-04, 3.7267e-06]) + tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, + 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) """.format( **factory_common_args ), From 3fbecdd2646f88fdb2ca62ccdbb1bdb0663da6bd Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:14 -0300 Subject: [PATCH 54/76] Update docstrings --- torch/signal/windows/windows.py | 42 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index e0c8d25d19298..6f1efe75c2358 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -3,7 +3,7 @@ from torch import Tensor from torch._prims_common import is_float_dtype -from torch._torch_docs import factory_common_args +from torch._torch_docs import factory_common_args, parse_kwargs, merge_dicts __all__ = [ 'cosine', @@ -11,6 +11,18 @@ 'gaussian', ] +window_common_args = merge_dicts( + parse_kwargs( + """ + M (int): the length of the output window. + In other words, the number of points of the exponential window. + sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. + If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. +""" + ), + factory_common_args +) + def _add_docstr(*args): r"""Adds docstrings to a given decorated function. @@ -23,11 +35,13 @@ def _add_docstr(*args): Args: args (str): """ + def decorator(o): o.__doc__ = "" for arg in args: o.__doc__ += arg return o + return decorator @@ -62,16 +76,12 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo r""" Args: - M (int): the length of the output window. - In other words, the number of points of the exponential window. + {M} center (float, optional): where the center of the window will be located. In other words, at which sample the peak of the window can be found. Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. tau (float, optional): the decay value. Default: 1.0. - sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. - If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. - """ + - r""" + {sym} .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even @@ -94,7 +104,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo tensor([4.5400e-05, 3.3546e-04, 2.4788e-03, 1.8316e-02, 1.3534e-01, 1.0000e+00, 1.3534e-01, 1.8316e-02, 2.4788e-03, 3.3546e-04]) """.format( - **factory_common_args + **window_common_args ), ) def exponential( @@ -160,10 +170,8 @@ def exponential( r""" Args: - M (int): the length of the output window. - In other words, the number of points of the cosine window. - sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. - If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. + {M} + {sym} .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even @@ -186,7 +194,7 @@ def exponential( tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, 0.4154]) """.format( - **factory_common_args + **window_common_args, ), ) def cosine(M: int, @@ -237,12 +245,10 @@ def cosine(M: int, r""" Args: - M (int): the length of the output window. - In other words, the number of points of the cosine window. + {M} std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. Default: 1.0. - sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. - If `True`, returns a symmetric window suitable for use in filter design. Default: `True` + {sym} .. note:: The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even @@ -265,7 +271,7 @@ def cosine(M: int, tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) """.format( - **factory_common_args + **window_common_args, ), ) def gaussian(M: int, From 9c116df1273e17d0fc6f1f296fdcaf1b6b010de7 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:14 -0300 Subject: [PATCH 55/76] Skip dtype torch.float16 --- torch/testing/_internal/opinfo/definitions/signal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 309eba9f95de9..71f1951b0fac2 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -180,6 +180,12 @@ def make_signal_windows_opinfo( "TestVmapOperatorsOpInfo", "test_op_has_batch_rule", ), + DecorateInfo( + unittest.skip("Skipped"), + "test_schema_correctness", + "TestSchemaCheckModeOpInfo", + dtypes=[torch.float16] + ), *skips, ), ) From 3364f0b932d2a50cea8b8b9bd61e1692a4f00ef7 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:14 -0300 Subject: [PATCH 56/76] Fix lint --- torch/testing/_internal/opinfo/definitions/signal.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 71f1951b0fac2..2e2659306ad0d 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -119,9 +119,10 @@ def make_signal_windows_ref(fn): Particularly used for window references that don't have a matching signature with torch, e.g., gaussian window. """ + def _fn(*args, **kwargs): # Remove torch-specific kwargs - for torch_key in {'device', 'layout', 'dtype', 'requires_grad'}: + for torch_key in {"device", "layout", "dtype", "requires_grad"}: if torch_key in kwargs: kwargs.pop(torch_key) return fn(*args, **kwargs) @@ -184,7 +185,7 @@ def make_signal_windows_opinfo( unittest.skip("Skipped"), "test_schema_correctness", "TestSchemaCheckModeOpInfo", - dtypes=[torch.float16] + dtypes=[torch.float16], ), *skips, ), From e1af0e8e960c35f2a7ab818a124b5936971faf69 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:15 -0300 Subject: [PATCH 57/76] Use math instead of numpy --- torch/signal/windows/windows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 6f1efe75c2358..f6db80c09e99b 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,5 +1,5 @@ import torch -import numpy as np +from math import sqrt from torch import Tensor from torch._prims_common import is_float_dtype @@ -298,7 +298,7 @@ def gaussian(M: int, start = -(M if not sym else M - 1) / 2.0 - constant = 1 / (std * np.sqrt(2)) + constant = 1 / (std * sqrt(2)) """ Note that non-integer step is subject to floating point rounding errors when comparing against end; From 75e18871ebc3f8f00562499a71da5d3ec67d63a1 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:15 -0300 Subject: [PATCH 58/76] Update DecorateInfo --- torch/testing/_internal/opinfo/definitions/signal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 2e2659306ad0d..ddfffd3bb34f7 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -182,10 +182,10 @@ def make_signal_windows_opinfo( "test_op_has_batch_rule", ), DecorateInfo( - unittest.skip("Skipped"), + unittest.skip("Skipped!"), + "TestSchemaCheckModeOpInfo" "test_schema_correctness", - "TestSchemaCheckModeOpInfo", - dtypes=[torch.float16], + dtypes=[torch.float16] ), *skips, ), From bbb20f7a49e37115b125e32883eac69878fc7fb4 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:16 -0300 Subject: [PATCH 59/76] Fix OpInfo --- torch/testing/_internal/opinfo/definitions/signal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index ddfffd3bb34f7..eb6db359dce8c 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -183,9 +183,9 @@ def make_signal_windows_opinfo( ), DecorateInfo( unittest.skip("Skipped!"), - "TestSchemaCheckModeOpInfo" + "TestSchemaCheckModeOpInfo", "test_schema_correctness", - dtypes=[torch.float16] + dtypes=[torch.float16], ), *skips, ), From 761ead28c02a35ef162de1b3e2e74dbb84023ac4 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:16 -0300 Subject: [PATCH 60/76] Expect failure --- torch/testing/_internal/opinfo/definitions/signal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index eb6db359dce8c..d0876a23f4da3 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -182,7 +182,7 @@ def make_signal_windows_opinfo( "test_op_has_batch_rule", ), DecorateInfo( - unittest.skip("Skipped!"), + unittest.expectedFailure, "TestSchemaCheckModeOpInfo", "test_schema_correctness", dtypes=[torch.float16], From 3cfee592133f1f368575e9ed413e7fd69d86ffb8 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:17 -0300 Subject: [PATCH 61/76] Add decorateinfo --- torch/testing/_internal/opinfo/definitions/signal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index d0876a23f4da3..4d67cbf642ebd 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -187,6 +187,12 @@ def make_signal_windows_opinfo( "test_schema_correctness", dtypes=[torch.float16], ), + DecorateInfo( + unittest.expectedFailure, + "TestDecomp", + "test_comprehensive", + dtypes=[torch.float16], + ), *skips, ), ) From e030843c041c87213c9fabb08a176e04c43ca7e5 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:17 -0300 Subject: [PATCH 62/76] Add device_type --- torch/testing/_internal/opinfo/definitions/signal.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 4d67cbf642ebd..5fe1ef9ee735a 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -186,12 +186,14 @@ def make_signal_windows_opinfo( "TestSchemaCheckModeOpInfo", "test_schema_correctness", dtypes=[torch.float16], + device_type="cpu", ), DecorateInfo( unittest.expectedFailure, "TestDecomp", "test_comprehensive", dtypes=[torch.float16], + device_type="cpu", ), *skips, ), From 1e2e1a6c74751d25d34d34e79fa6d2db89f41b72 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:18 -0300 Subject: [PATCH 63/76] Address review --- torch/signal/windows/windows.py | 126 ++++++++---------- .../_internal/opinfo/definitions/signal.py | 25 +--- 2 files changed, 60 insertions(+), 91 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index f6db80c09e99b..616eb62f5608c 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -14,13 +14,15 @@ window_common_args = merge_dicts( parse_kwargs( """ - M (int): the length of the output window. + M (int): the length of the window. In other words, the number of points of the exponential window. sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. """ ), - factory_common_args + factory_common_args, + {"normalization": "The window is normalized to 1 (maximum value is 1). However, the 1 doesn't appear if " + "`M` is even and `sym` is `True`."} ) @@ -37,9 +39,7 @@ def _add_docstr(*args): """ def decorator(o): - o.__doc__ = "" - for arg in args: - o.__doc__ += arg + o.__doc__ = "".join(args) return o return decorator @@ -71,48 +71,45 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo The exponential window is defined as follows: .. math:: - w(n) = \exp{\left(-\frac{|n - center|}{\tau}\right)} + w(n) = \exp{\left(-\frac{|n - c|}{\tau}\right)} + +Where `c` is the center of the window. """, r""" +{normalization} + Args: {M} + +Keyword args: center (float, optional): where the center of the window will be located. - In other words, at which sample the peak of the window can be found. Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. tau (float, optional): the decay value. Default: 1.0. {sym} - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `sym` is `True`. - -Keyword args: {dtype} {layout} {device} {requires_grad} -Examples: +Examples:: >>> # Generate an exponential window without keyword args. >>> torch.signal.windows.exponential(10) - tensor([0.0111, 0.0302, 0.0821, 0.2231, 0.6065, 0.6065, 0.2231, 0.0821, 0.0302, - 0.0111]) + tensor([0.0111, 0.0302, 0.0821, 0.2231, 0.6065, 0.6065, 0.2231, 0.0821, 0.0302, 0.0111]) >>> # Generate a periodic exponential window and decay factor equal to .5 >>> torch.signal.windows.exponential(10,sym=False,tau=.5) - tensor([4.5400e-05, 3.3546e-04, 2.4788e-03, 1.8316e-02, 1.3534e-01, 1.0000e+00, - 1.3534e-01, 1.8316e-02, 2.4788e-03, 3.3546e-04]) + tensor([4.5400e-05, 3.3546e-04, 2.4788e-03, 1.8316e-02, 1.3534e-01, 1.0000e+00, 1.3534e-01, 1.8316e-02, 2.4788e-03, 3.3546e-04]) """.format( **window_common_args ), ) def exponential( M: int, + *, center: float = None, tau: float = 1.0, sym: bool = True, - *, dtype: torch.dtype = None, layout: torch.layout = torch.strided, device: torch.device = None, @@ -126,17 +123,14 @@ def exponential( if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if M == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if tau <= 0: raise ValueError(f'Tau must be positive, got: {tau} instead.') if not sym and center is not None: - raise ValueError('Center must be \'None\' for non-symmetric windows') + raise ValueError('Center must be None for non-symmetric windows') if center is None: - center = -(M if not sym else M - 1) / 2.0 + center = -(M if not sym and M > 1 else M - 1) / 2.0 constant = 1 / tau @@ -164,46 +158,42 @@ def exponential( .. math:: w(n) = \cos{\left(\frac{\pi n}{M} - \frac{\pi}{2}\right)} = \sin{\left(\frac{\pi n}{M}\right)} - -Where `M` is the length of the window. """, r""" +{normalization} + Args: {M} - {sym} - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `sym` is `True`. Keyword args: + {sym} {dtype} {layout} {device} {requires_grad} -Examples: +Examples:: >>> # Generate a cosine window without keyword args. >>> torch.signal.windows.cosine(10) - tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, - 0.1564]) + tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) >>> # Generate a periodic cosine window. >>> torch.signal.windows.cosine(10,sym=False) - tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, - 0.4154]) + tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, 0.4154]) """.format( **window_common_args, ), ) -def cosine(M: int, - sym: bool = True, - *, - dtype: torch.dtype = None, - layout: torch.layout = torch.strided, - device: torch.device = None, - requires_grad: bool = False) -> Tensor: +def cosine( + M: int, + *, + sym: bool = True, + dtype: torch.dtype = None, + layout: torch.layout = torch.strided, + device: torch.device = None, + requires_grad: bool = False +) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() @@ -212,11 +202,8 @@ def cosine(M: int, if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if M == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - start = 0.5 - constant = torch.pi / (M + 1 if not sym else M) + constant = torch.pi / (M + 1 if not sym and M > 1 else M) """ Note that non-integer step is subject to floating point rounding errors when comparing against end; @@ -241,47 +228,45 @@ def cosine(M: int, .. math:: w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} - """, - r""" +{normalization} + """, + r""" + Args: {M} + +Keyword args: std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. Default: 1.0. {sym} - -.. note:: - The window is normalized to 1 (maximum value is 1), however, the 1 doesn't appear if `M` is even - and `sym` is `True`. - -Keyword args: {dtype} {layout} {device} {requires_grad} -Examples: +Examples:: >>> # Generate a gaussian window without keyword args. >>> torch.signal.windows.gaussian(10) - tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, - 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) + tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) >>> # Generate a periodic gaussian window and standard deviation equal to 0.9. >>> torch.signal.windows.gaussian(10,sym=False,std=0.9) - tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, - 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) + tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) """.format( **window_common_args, ), ) -def gaussian(M: int, - std: float = 1.0, - sym: bool = True, - *, - dtype: torch.dtype = None, - layout: torch.layout = torch.strided, - device: torch.device = None, - requires_grad: bool = False) -> Tensor: +def gaussian( + M: int, + *, + std: float = 1.0, + sym: bool = True, + dtype: torch.dtype = None, + layout: torch.layout = torch.strided, + device: torch.device = None, + requires_grad: bool = False +) -> Tensor: if dtype is None: dtype = torch.get_default_dtype() @@ -290,13 +275,10 @@ def gaussian(M: int, if M == 0: return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if M == 1: - return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) - if std <= 0: raise ValueError(f'Standard deviation must be positive, got: {std} instead.') - start = -(M if not sym else M - 1) / 2.0 + start = -(M if not sym and M > 1 else M - 1) / 2.0 constant = 1 / (std * sqrt(2)) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 5fe1ef9ee735a..8a2b7e95c47c1 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -26,21 +26,8 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) additional keyword arguments. """ - # Test a window size of length zero and one. - # If it's either symmetric or not doesn't matter in these sample inputs. - for size in range(2): - yield SampleInput( - size, - *args, - device=device, - dtype=dtype, - requires_grad=requires_grad, - **kwargs, - ) - - # For sizes larger than 1 we need to test both symmetric and non-symmetric windows. - # Note: sample input tensors must be kept rather small. - for size, sym in product(list(range(2, 6)), (True, False)): + # Tests window sizes up to 5 samples. + for size, sym in product(range(6), (True, False)): yield SampleInput( size, *args, @@ -97,7 +84,7 @@ def error_inputs_exponential_window(op_info, device, **kwargs): yield ErrorInput( SampleInput(3, center=1, sym=False, dtype=torch.float32, device=device), error_type=ValueError, - error_regex="Center must be 'None' for non-symmetric windows", + error_regex="Center must be None for non-symmetric windows", ) @@ -203,19 +190,19 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( name="signal.windows.cosine", - ref=make_signal_windows_ref(scipy.signal.windows.cosine), + ref=make_signal_windows_ref(scipy.signal.windows.cosine) if TEST_SCIPY else None, sample_inputs_func=sample_inputs_window, error_inputs_func=error_inputs_window, ), make_signal_windows_opinfo( name="signal.windows.exponential", - ref=make_signal_windows_ref(scipy.signal.windows.exponential), + ref=make_signal_windows_ref(scipy.signal.windows.exponential) if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), error_inputs_func=error_inputs_exponential_window, ), make_signal_windows_opinfo( name="signal.windows.gaussian", - ref=make_signal_windows_ref(scipy.signal.windows.gaussian), + ref=make_signal_windows_ref(scipy.signal.windows.gaussian) if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, std=random.uniform(0, 3)), error_inputs_func=error_inputs_gaussian_window, ), From ca792416704775076f7853350151048bb4b0ce44 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:18 -0300 Subject: [PATCH 64/76] Fix lint err --- torch/signal/windows/windows.py | 8 ++++---- torch/testing/_internal/opinfo/definitions/signal.py | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 616eb62f5608c..458768618ca39 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -81,7 +81,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo Args: {M} - + Keyword args: center (float, optional): where the center of the window will be located. Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. @@ -162,7 +162,7 @@ def exponential( r""" {normalization} - + Args: {M} @@ -231,8 +231,8 @@ def cosine( {normalization} """, - r""" - + r""" + Args: {M} diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 8a2b7e95c47c1..8dc8e575aa4a5 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -190,19 +190,25 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( name="signal.windows.cosine", - ref=make_signal_windows_ref(scipy.signal.windows.cosine) if TEST_SCIPY else None, + ref=make_signal_windows_ref(scipy.signal.windows.cosine) + if TEST_SCIPY + else None, sample_inputs_func=sample_inputs_window, error_inputs_func=error_inputs_window, ), make_signal_windows_opinfo( name="signal.windows.exponential", - ref=make_signal_windows_ref(scipy.signal.windows.exponential) if TEST_SCIPY else None, + ref=make_signal_windows_ref(scipy.signal.windows.exponential) + if TEST_SCIPY + else None, sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), error_inputs_func=error_inputs_exponential_window, ), make_signal_windows_opinfo( name="signal.windows.gaussian", - ref=make_signal_windows_ref(scipy.signal.windows.gaussian) if TEST_SCIPY else None, + ref=make_signal_windows_ref(scipy.signal.windows.gaussian) + if TEST_SCIPY + else None, sample_inputs_func=partial(sample_inputs_window, std=random.uniform(0, 3)), error_inputs_func=error_inputs_gaussian_window, ), From 2f8257942e90c5a1514d0302528988f701a08745 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 14:15:19 -0300 Subject: [PATCH 65/76] Address review and fix lint --- torch/signal/windows/windows.py | 6 +++--- .../_internal/opinfo/definitions/signal.py | 15 +++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 458768618ca39..fd62ea5a2c6f3 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -73,7 +73,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo .. math:: w(n) = \exp{\left(-\frac{|n - c|}{\tau}\right)} -Where `c` is the center of the window. +where `c` is the center of the window. """, r""" @@ -228,11 +228,11 @@ def cosine( .. math:: w(n) = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} - -{normalization} """, r""" +{normalization} + Args: {M} diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 8dc8e575aa4a5..3689ff66b30f7 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -103,15 +103,18 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): def make_signal_windows_ref(fn): r"""Wrapper for signal window references. - Particularly used for window references that don't have a matching signature with + Discards keyword arguments for window reference functions that don't have a matching signature with torch, e.g., gaussian window. """ - def _fn(*args, **kwargs): - # Remove torch-specific kwargs - for torch_key in {"device", "layout", "dtype", "requires_grad"}: - if torch_key in kwargs: - kwargs.pop(torch_key) + def _fn( + *args, + dtype=None, + device=None, + layout=torch.strided, + requires_grad=False, + **kwargs, + ): return fn(*args, **kwargs) return _fn From f29e59d9d54d8d4f340472f4266fa43dbb7f6daa Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 17:29:35 -0300 Subject: [PATCH 66/76] Expected failure test_meta torch.half --- .../testing/_internal/opinfo/definitions/signal.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 3689ff66b30f7..b8fa78c95c076 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -185,6 +185,20 @@ def make_signal_windows_opinfo( dtypes=[torch.float16], device_type="cpu", ), + DecorateInfo( + unittest.expectedFailure, + "TestMeta", + "test_dispatch_meta", + dtypes=[torch.float16], + device_type="cpu", + ), + DecorateInfo( + unittest.expectedFailure, + "TestMeta", + "test_meta", + dtypes=[torch.float16], + device_type="cpu", + ), *skips, ), ) From a6103f982d447b13d1d206f442a1fe3331dfe3df Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Tue, 11 Oct 2022 21:34:43 -0300 Subject: [PATCH 67/76] Update tests and index --- docs/source/index.rst | 2 +- torch/signal/windows/windows.py | 1 + torch/testing/_internal/opinfo/definitions/signal.py | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 2c0390434d50c..b9d097f551913 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -78,8 +78,8 @@ Features described in this documentation are classified by release status: torch.jit torch.linalg torch.monitor - torch.special torch.signal + torch.special torch.overrides torch.package profiler diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index fd62ea5a2c6f3..849f057e900f2 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -5,6 +5,7 @@ from torch._prims_common import is_float_dtype from torch._torch_docs import factory_common_args, parse_kwargs, merge_dicts + __all__ = [ 'cosine', 'exponential', diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index b8fa78c95c076..40e11232e4f90 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -199,6 +199,13 @@ def make_signal_windows_opinfo( dtypes=[torch.float16], device_type="cpu", ), + DecorateInfo( + unittest.expectedFailure, + "TestNNCOpInfo", + "test_nnc_correctness", + dtypes=[torch.float16], + device_type="cpu", + ), *skips, ), ) From 04851f80836160c91914c8b0a03ec2d61ace14d5 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Wed, 12 Oct 2022 22:16:58 -0300 Subject: [PATCH 68/76] Address comments --- torch/signal/windows/windows.py | 21 +++++++++++-------- .../_internal/opinfo/definitions/signal.py | 10 +++++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 849f057e900f2..1c2ab57fcd413 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -16,7 +16,7 @@ parse_kwargs( """ M (int): the length of the window. - In other words, the number of points of the exponential window. + In other words, the number of points of the returned window. sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. """ @@ -38,7 +38,6 @@ def _add_docstr(*args): Args: args (str): """ - def decorator(o): o.__doc__ = "".join(args) return o @@ -48,13 +47,13 @@ def decorator(o): def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layout: torch.layout) -> None: r"""Performs common checks for all the defined windows. - This function should be called before computing any window + This function should be called before computing any window. Args: function_name (str): name of the window function. M (int): length of the window. - dtype (:class:`torch.dtype`): the desired data type of the window tensor. - layout (:class:`torch.layout`): the desired layout of the window tensor. + dtype (:class:`torch.dtype`): the desired data type of returned tensor. + layout (:class:`torch.layout`): the desired layout of returned tensor. """ if M < 0: raise ValueError(f'{function_name} requires non-negative window length, got M={M}') @@ -86,7 +85,10 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo Keyword args: center (float, optional): where the center of the window will be located. Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. - tau (float, optional): the decay value. Default: 1.0. + tau (float, optional): the decay value. + Tau is generally associated with a percentage, that means, that the value should + vary within the interval (0, 100]. If tau is 100, it is considered the uniform window. + Default: 1.0. {sym} {dtype} {layout} @@ -94,7 +96,8 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo {requires_grad} Examples:: - >>> # Generate an exponential window without keyword args. + >>> # Generate a symmetric exponential window of size 10 and with a decay value of 1.0. + >>> # The center will be at (M - 1) / 2, where M is 10. >>> torch.signal.windows.exponential(10) tensor([0.0111, 0.0302, 0.0821, 0.2231, 0.6065, 0.6065, 0.2231, 0.0821, 0.0302, 0.0111]) @@ -175,7 +178,7 @@ def exponential( {requires_grad} Examples:: - >>> # Generate a cosine window without keyword args. + >>> # Generate a symmetric cosine window. >>> torch.signal.windows.cosine(10) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) @@ -247,7 +250,7 @@ def cosine( {requires_grad} Examples:: - >>> # Generate a gaussian window without keyword args. + >>> # Generate a symmetric gaussian window with a standard deviation of 1.0. >>> torch.signal.windows.gaussian(10) tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 40e11232e4f90..a40df876b58ce 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -5,6 +5,8 @@ from itertools import product from typing import List +import numpy + import torch from torch.testing._internal.common_utils import TEST_SCIPY from torch.testing._internal.opinfo.core import ( @@ -109,13 +111,13 @@ def make_signal_windows_ref(fn): def _fn( *args, - dtype=None, + dtype=numpy.float64, device=None, layout=torch.strided, requires_grad=False, **kwargs, ): - return fn(*args, **kwargs) + return fn(*args, **kwargs).astype(dtype) return _fn @@ -225,7 +227,7 @@ def make_signal_windows_opinfo( ref=make_signal_windows_ref(scipy.signal.windows.exponential) if TEST_SCIPY else None, - sample_inputs_func=partial(sample_inputs_window, tau=random.uniform(0, 10)), + sample_inputs_func=partial(sample_inputs_window, tau=2.78), error_inputs_func=error_inputs_exponential_window, ), make_signal_windows_opinfo( @@ -233,7 +235,7 @@ def make_signal_windows_opinfo( ref=make_signal_windows_ref(scipy.signal.windows.gaussian) if TEST_SCIPY else None, - sample_inputs_func=partial(sample_inputs_window, std=random.uniform(0, 3)), + sample_inputs_func=partial(sample_inputs_window, std=1.92), error_inputs_func=error_inputs_gaussian_window, ), ] From d7ea5a3faef3ef2c12bb836bdb2ce6070183a826 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Wed, 12 Oct 2022 22:18:20 -0300 Subject: [PATCH 69/76] Remove random --- torch/testing/_internal/opinfo/definitions/signal.py | 1 - 1 file changed, 1 deletion(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index a40df876b58ce..cff7259ac2c65 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -1,4 +1,3 @@ -import random import unittest from functools import partial From db86f808abf5e8515e05a8caaf13d79d12e2439b Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Wed, 12 Oct 2022 22:27:34 -0300 Subject: [PATCH 70/76] Reorder op_db --- torch/testing/_internal/opinfo/definitions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torch/testing/_internal/opinfo/definitions/__init__.py b/torch/testing/_internal/opinfo/definitions/__init__.py index f718c125730e9..5b2ed8d391b4f 100644 --- a/torch/testing/_internal/opinfo/definitions/__init__.py +++ b/torch/testing/_internal/opinfo/definitions/__init__.py @@ -13,8 +13,8 @@ op_db: List[OpInfo] = [ *fft.op_db, *linalg.op_db, - *special.op_db, *signal.op_db, + *special.op_db, *_masked.op_db, ] From ce4bb652a475206dba7e2ded8dbc8ac712245b78 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Thu, 13 Oct 2022 01:23:41 -0300 Subject: [PATCH 71/76] Fix bug and add tests --- torch/signal/windows/windows.py | 12 ++-- .../_internal/opinfo/definitions/signal.py | 70 +++++++++++++++++-- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 1c2ab57fcd413..9c12c8c5ab92a 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -85,7 +85,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo Keyword args: center (float, optional): where the center of the window will be located. Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. - tau (float, optional): the decay value. + tau (float, optional): the decay value. Tau is generally associated with a percentage, that means, that the value should vary within the interval (0, 100]. If tau is 100, it is considered the uniform window. Default: 1.0. @@ -130,11 +130,11 @@ def exponential( if tau <= 0: raise ValueError(f'Tau must be positive, got: {tau} instead.') - if not sym and center is not None: - raise ValueError('Center must be None for non-symmetric windows') + if sym and center is not None: + raise ValueError('Center must be None for symmetric windows') if center is None: - center = -(M if not sym and M > 1 else M - 1) / 2.0 + center = (M if not sym and M > 1 else M - 1) / 2.0 constant = 1 / tau @@ -142,8 +142,8 @@ def exponential( Note that non-integer step is subject to floating point rounding errors when comparing against end; thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ - k = torch.arange(start=center * constant, - end=(center + (M - 1)) * constant + constant / 2, + k = torch.arange(start=-center * constant, + end=(-center + (M - 1)) * constant + constant / 2, step=constant, dtype=dtype, layout=layout, diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index cff7259ac2c65..05460c1b651ab 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -40,6 +40,61 @@ def sample_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs) ) +def reference_inputs_window(op_info, device, dtype, requires_grad, *args, **kwargs): + r"""Reference inputs function to use for windows which have a common signature, i.e., + window size and sym only. + + Implement other special functions for windows that have a specific signature. + See exponential and gaussian windows for instance. + """ + yield from sample_inputs_window( + op_info, device, dtype, requires_grad, *args, **kwargs + ) + + cases = (8, 16, 32, 64, 128, 256) + + for size in cases: + yield SampleInput(size, sym=False) + yield SampleInput(size, sym=True) + + +def reference_inputs_exponential_window( + op_info, device, dtype, requires_grad, **kwargs +): + yield from sample_inputs_window(op_info, device, dtype, requires_grad, **kwargs) + + cases = ( + (8, {"center": 4, "tau": 0.5}), + (16, {"center": 8, "tau": 2.5}), + (32, {"center": 16, "tau": 43.5}), + (64, {"center": 20, "tau": 3.7}), + (128, {"center": 62, "tau": 99}), + (256, {"tau": 10}), + ) + + for size, kw in cases: + yield SampleInput(size, sym=False, **kw) + kw["center"] = None + yield SampleInput(size, sym=True, **kw) + + +def reference_inputs_gaussian_window(op_info, device, dtype, requires_grad, **kwargs): + yield from sample_inputs_window(op_info, device, dtype, requires_grad, **kwargs) + + cases = ( + (8, {"std": 0.1}), + (16, {"std": 1.2}), + (32, {"std": 2.1}), + (64, {"std": 3.9}), + (128, {"std": 4.5}), + (256, {"std": 10}), + ) + + for size, kw in cases: + yield SampleInput(size, sym=False, **kw) + yield SampleInput(size, sym=True, **kw) + + def error_inputs_window(op_info, device, *args, **kwargs): # Tests for windows that have a negative size yield ErrorInput( @@ -81,11 +136,11 @@ def error_inputs_exponential_window(op_info, device, **kwargs): error_regex="Tau must be positive, got: -1 instead.", ) - # Tests for non-symmetric windows and a given center value. + # Tests for symmetric windows and a given center value. yield ErrorInput( - SampleInput(3, center=1, sym=False, dtype=torch.float32, device=device), + SampleInput(3, center=1, sym=True, dtype=torch.float32, device=device), error_type=ValueError, - error_regex="Center must be None for non-symmetric windows", + error_regex="Center must be None for symmetric windows", ) @@ -102,7 +157,7 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): def make_signal_windows_ref(fn): - r"""Wrapper for signal window references. + r"""Wrapper for scipy signal window references. Discards keyword arguments for window reference functions that don't have a matching signature with torch, e.g., gaussian window. @@ -116,13 +171,14 @@ def _fn( requires_grad=False, **kwargs, ): + r"""The unused arguments are defined to disregard those values""" return fn(*args, **kwargs).astype(dtype) return _fn def make_signal_windows_opinfo( - name, ref, sample_inputs_func, error_inputs_func, *, skips=() + name, ref, sample_inputs_func, reference_inputs_func, error_inputs_func, *, skips=() ): r"""Helper function to create OpInfo objects related to different windows.""" return OpInfo( @@ -131,6 +187,7 @@ def make_signal_windows_opinfo( dtypes=floating_types_and(torch.bfloat16, torch.float16), dtypesIfCUDA=floating_types_and(torch.bfloat16, torch.float16), sample_inputs_func=sample_inputs_func, + reference_inputs_func=reference_inputs_func, error_inputs_func=error_inputs_func, supports_out=False, supports_autograd=False, @@ -219,6 +276,7 @@ def make_signal_windows_opinfo( if TEST_SCIPY else None, sample_inputs_func=sample_inputs_window, + reference_inputs_func=reference_inputs_window, error_inputs_func=error_inputs_window, ), make_signal_windows_opinfo( @@ -227,6 +285,7 @@ def make_signal_windows_opinfo( if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, tau=2.78), + reference_inputs_func=partial(reference_inputs_exponential_window, tau=2.78), error_inputs_func=error_inputs_exponential_window, ), make_signal_windows_opinfo( @@ -235,6 +294,7 @@ def make_signal_windows_opinfo( if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, std=1.92), + reference_inputs_func=partial(reference_inputs_gaussian_window, std=1.92), error_inputs_func=error_inputs_gaussian_window, ), ] From 10a0b14b9a9fc56f308a659f81bdc1ab5e8fbeb4 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Thu, 13 Oct 2022 01:42:23 -0300 Subject: [PATCH 72/76] Add Optional --- torch/signal/windows/windows.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 9c12c8c5ab92a..45eec2c1196e7 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -1,3 +1,5 @@ +from typing import Optional + import torch from math import sqrt @@ -111,12 +113,12 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo def exponential( M: int, *, - center: float = None, + center: Optional[float] = None, tau: float = 1.0, sym: bool = True, - dtype: torch.dtype = None, + dtype: Optional[torch.dtype] = None, layout: torch.layout = torch.strided, - device: torch.device = None, + device: Optional[torch.device] = None, requires_grad: bool = False ) -> Tensor: if dtype is None: @@ -193,9 +195,9 @@ def cosine( M: int, *, sym: bool = True, - dtype: torch.dtype = None, + dtype: Optional[torch.dtype] = None, layout: torch.layout = torch.strided, - device: torch.device = None, + device: Optional[torch.device] = None, requires_grad: bool = False ) -> Tensor: if dtype is None: @@ -266,9 +268,9 @@ def gaussian( *, std: float = 1.0, sym: bool = True, - dtype: torch.dtype = None, + dtype: Optional[torch.dtype] = None, layout: torch.layout = torch.strided, - device: torch.device = None, + device: Optional[torch.device] = None, requires_grad: bool = False ) -> Tensor: if dtype is None: From 77bf43b9b795ec0d42d7746d2b00ccd9dc40cf35 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Thu, 13 Oct 2022 18:22:46 -0300 Subject: [PATCH 73/76] Replace arange with linspace --- torch/signal/windows/windows.py | 55 +++++++++---------- .../_internal/opinfo/definitions/signal.py | 12 +++- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/torch/signal/windows/windows.py b/torch/signal/windows/windows.py index 45eec2c1196e7..06bd710a34510 100644 --- a/torch/signal/windows/windows.py +++ b/torch/signal/windows/windows.py @@ -7,7 +7,6 @@ from torch._prims_common import is_float_dtype from torch._torch_docs import factory_common_args, parse_kwargs, merge_dicts - __all__ = [ 'cosine', 'exponential', @@ -40,6 +39,7 @@ def _add_docstr(*args): Args: args (str): """ + def decorator(o): o.__doc__ = "".join(args) return o @@ -98,6 +98,7 @@ def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layo {requires_grad} Examples:: + >>> # Generate a symmetric exponential window of size 10 and with a decay value of 1.0. >>> # The center will be at (M - 1) / 2, where M is 10. >>> torch.signal.windows.exponential(10) @@ -144,13 +145,13 @@ def exponential( Note that non-integer step is subject to floating point rounding errors when comparing against end; thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. """ - k = torch.arange(start=-center * constant, - end=(-center + (M - 1)) * constant + constant / 2, - step=constant, - dtype=dtype, - layout=layout, - device=device, - requires_grad=requires_grad) + k = torch.linspace(start=-center * constant, + end=(-center + (M - 1)) * constant, + steps=M, + dtype=dtype, + layout=layout, + device=device, + requires_grad=requires_grad) return torch.exp(-torch.abs(k)) @@ -180,6 +181,7 @@ def exponential( {requires_grad} Examples:: + >>> # Generate a symmetric cosine window. >>> torch.signal.windows.cosine(10) tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) @@ -211,17 +213,13 @@ def cosine( start = 0.5 constant = torch.pi / (M + 1 if not sym and M > 1 else M) - """ - Note that non-integer step is subject to floating point rounding errors when comparing against end; - thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. - """ - k = torch.arange(start=start * constant, - end=(start + (M - 1)) * constant + constant / 2, - step=constant, - dtype=dtype, - layout=layout, - device=device, - requires_grad=requires_grad) + k = torch.linspace(start=start * constant, + end=(start + (M - 1)) * constant, + steps=M, + dtype=dtype, + layout=layout, + device=device, + requires_grad=requires_grad) return torch.sin(k) @@ -252,6 +250,7 @@ def cosine( {requires_grad} Examples:: + >>> # Generate a symmetric gaussian window with a standard deviation of 1.0. >>> torch.signal.windows.gaussian(10) tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) @@ -288,16 +287,12 @@ def gaussian( constant = 1 / (std * sqrt(2)) - """ - Note that non-integer step is subject to floating point rounding errors when comparing against end; - thus, to avoid inconsistency, we added an epsilon equal to `step / 2` to `end`. - """ - k = torch.arange(start=start * constant, - end=(start + (M - 1)) * constant + constant / 2, - step=constant, - dtype=dtype, - layout=layout, - device=device, - requires_grad=requires_grad) + k = torch.linspace(start=start * constant, + end=(start + (M - 1)) * constant, + steps=M, + dtype=dtype, + layout=layout, + device=device, + requires_grad=requires_grad) return torch.exp(-k ** 2) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 05460c1b651ab..f1209ca5e4f92 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -2,7 +2,7 @@ from functools import partial from itertools import product -from typing import List +from typing import Callable, List, Tuple import numpy @@ -156,7 +156,7 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): ) -def make_signal_windows_ref(fn): +def make_signal_windows_ref(fn: Callable): r"""Wrapper for scipy signal window references. Discards keyword arguments for window reference functions that don't have a matching signature with @@ -178,7 +178,13 @@ def _fn( def make_signal_windows_opinfo( - name, ref, sample_inputs_func, reference_inputs_func, error_inputs_func, *, skips=() + name: str, + ref: Callable, + sample_inputs_func: Callable, + reference_inputs_func: Callable, + error_inputs_func: Callable, + *, + skips: Tuple[DecorateInfo] = (), ): r"""Helper function to create OpInfo objects related to different windows.""" return OpInfo( From 21dd563bbfcdd1a5dddef74cd0f4b244e3eabd0c Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Thu, 13 Oct 2022 18:34:40 -0300 Subject: [PATCH 74/76] Change signature --- torch/testing/_internal/opinfo/definitions/signal.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index f1209ca5e4f92..6e5117db6d2dd 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -156,7 +156,7 @@ def error_inputs_gaussian_window(op_info, device, **kwargs): ) -def make_signal_windows_ref(fn: Callable): +def reference_signal_window(fn: Callable): r"""Wrapper for scipy signal window references. Discards keyword arguments for window reference functions that don't have a matching signature with @@ -278,7 +278,7 @@ def make_signal_windows_opinfo( op_db: List[OpInfo] = [ make_signal_windows_opinfo( name="signal.windows.cosine", - ref=make_signal_windows_ref(scipy.signal.windows.cosine) + ref=reference_signal_window(scipy.signal.windows.cosine) if TEST_SCIPY else None, sample_inputs_func=sample_inputs_window, @@ -287,7 +287,7 @@ def make_signal_windows_opinfo( ), make_signal_windows_opinfo( name="signal.windows.exponential", - ref=make_signal_windows_ref(scipy.signal.windows.exponential) + ref=reference_signal_window(scipy.signal.windows.exponential) if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, tau=2.78), @@ -296,7 +296,7 @@ def make_signal_windows_opinfo( ), make_signal_windows_opinfo( name="signal.windows.gaussian", - ref=make_signal_windows_ref(scipy.signal.windows.gaussian) + ref=reference_signal_window(scipy.signal.windows.gaussian) if TEST_SCIPY else None, sample_inputs_func=partial(sample_inputs_window, std=1.92), From 7df83fcdb7ae06954093a537ba962ef73f0d2dd3 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Thu, 13 Oct 2022 22:32:11 -0300 Subject: [PATCH 75/76] rerun checks From e399648c350b84bd72ab80f1e11b66531325ad50 Mon Sep 17 00:00:00 2001 From: Alvaro Gaona Date: Fri, 14 Oct 2022 00:14:52 -0300 Subject: [PATCH 76/76] Skip test_dispatch_symbolic_meta --- torch/testing/_internal/opinfo/definitions/signal.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/torch/testing/_internal/opinfo/definitions/signal.py b/torch/testing/_internal/opinfo/definitions/signal.py index 6e5117db6d2dd..1f1c8d7e6a6d1 100644 --- a/torch/testing/_internal/opinfo/definitions/signal.py +++ b/torch/testing/_internal/opinfo/definitions/signal.py @@ -263,6 +263,13 @@ def make_signal_windows_opinfo( dtypes=[torch.float16], device_type="cpu", ), + DecorateInfo( + unittest.expectedFailure, + "TestMeta", + "test_dispatch_symbolic_meta", + dtypes=[torch.float16], + device_type="cpu", + ), DecorateInfo( unittest.expectedFailure, "TestNNCOpInfo",