torchaudio 2.7.1__cp313-cp313t-win_amd64.whl → 2.9.0__cp313-cp313t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of torchaudio might be problematic. Click here for more details.

Files changed (92) hide show
  1. torchaudio/__init__.py +184 -33
  2. torchaudio/_extension/__init__.py +1 -14
  3. torchaudio/_extension/utils.py +0 -47
  4. torchaudio/_internal/module_utils.py +68 -10
  5. torchaudio/_torchcodec.py +340 -0
  6. torchaudio/datasets/cmuarctic.py +1 -1
  7. torchaudio/datasets/utils.py +1 -1
  8. torchaudio/functional/__init__.py +6 -3
  9. torchaudio/functional/_alignment.py +1 -1
  10. torchaudio/functional/filtering.py +70 -55
  11. torchaudio/functional/functional.py +31 -61
  12. torchaudio/lib/_torchaudio.pyd +0 -0
  13. torchaudio/lib/libtorchaudio.pyd +0 -0
  14. torchaudio/models/decoder/__init__.py +19 -1
  15. torchaudio/models/decoder/_ctc_decoder.py +6 -6
  16. torchaudio/models/decoder/_cuda_ctc_decoder.py +1 -1
  17. torchaudio/models/squim/objective.py +2 -2
  18. torchaudio/pipelines/_source_separation_pipeline.py +1 -1
  19. torchaudio/pipelines/_squim_pipeline.py +2 -2
  20. torchaudio/pipelines/_tts/utils.py +3 -1
  21. torchaudio/pipelines/rnnt_pipeline.py +4 -4
  22. torchaudio/transforms/__init__.py +4 -1
  23. torchaudio/transforms/_transforms.py +4 -3
  24. torchaudio/utils/__init__.py +2 -9
  25. torchaudio/utils/download.py +1 -1
  26. torchaudio/version.py +2 -2
  27. {torchaudio-2.7.1.dist-info → torchaudio-2.9.0.dist-info}/METADATA +15 -7
  28. torchaudio-2.9.0.dist-info/RECORD +85 -0
  29. {torchaudio-2.7.1.dist-info → torchaudio-2.9.0.dist-info}/top_level.txt +0 -1
  30. torchaudio/_backend/__init__.py +0 -61
  31. torchaudio/_backend/backend.py +0 -53
  32. torchaudio/_backend/common.py +0 -52
  33. torchaudio/_backend/ffmpeg.py +0 -334
  34. torchaudio/_backend/soundfile.py +0 -54
  35. torchaudio/_backend/soundfile_backend.py +0 -457
  36. torchaudio/_backend/sox.py +0 -91
  37. torchaudio/_backend/utils.py +0 -317
  38. torchaudio/backend/__init__.py +0 -8
  39. torchaudio/backend/_no_backend.py +0 -25
  40. torchaudio/backend/_sox_io_backend.py +0 -294
  41. torchaudio/backend/common.py +0 -13
  42. torchaudio/backend/no_backend.py +0 -14
  43. torchaudio/backend/soundfile_backend.py +0 -14
  44. torchaudio/backend/sox_io_backend.py +0 -14
  45. torchaudio/io/__init__.py +0 -13
  46. torchaudio/io/_effector.py +0 -347
  47. torchaudio/io/_playback.py +0 -72
  48. torchaudio/kaldi_io.py +0 -144
  49. torchaudio/prototype/__init__.py +0 -0
  50. torchaudio/prototype/datasets/__init__.py +0 -4
  51. torchaudio/prototype/datasets/musan.py +0 -67
  52. torchaudio/prototype/functional/__init__.py +0 -26
  53. torchaudio/prototype/functional/_dsp.py +0 -433
  54. torchaudio/prototype/functional/_rir.py +0 -379
  55. torchaudio/prototype/functional/functional.py +0 -190
  56. torchaudio/prototype/models/__init__.py +0 -36
  57. torchaudio/prototype/models/_conformer_wav2vec2.py +0 -794
  58. torchaudio/prototype/models/_emformer_hubert.py +0 -333
  59. torchaudio/prototype/models/conv_emformer.py +0 -525
  60. torchaudio/prototype/models/hifi_gan.py +0 -336
  61. torchaudio/prototype/models/rnnt.py +0 -711
  62. torchaudio/prototype/models/rnnt_decoder.py +0 -399
  63. torchaudio/prototype/pipelines/__init__.py +0 -12
  64. torchaudio/prototype/pipelines/_vggish/__init__.py +0 -3
  65. torchaudio/prototype/pipelines/_vggish/_vggish_impl.py +0 -233
  66. torchaudio/prototype/pipelines/_vggish/_vggish_pipeline.py +0 -82
  67. torchaudio/prototype/pipelines/hifigan_pipeline.py +0 -228
  68. torchaudio/prototype/pipelines/rnnt_pipeline.py +0 -58
  69. torchaudio/prototype/transforms/__init__.py +0 -9
  70. torchaudio/prototype/transforms/_transforms.py +0 -456
  71. torchaudio/sox_effects/__init__.py +0 -10
  72. torchaudio/sox_effects/sox_effects.py +0 -272
  73. torchaudio/utils/ffmpeg_utils.py +0 -11
  74. torchaudio/utils/sox_utils.py +0 -99
  75. torchaudio-2.7.1.dist-info/RECORD +0 -144
  76. torio/__init__.py +0 -8
  77. torio/_extension/__init__.py +0 -13
  78. torio/_extension/utils.py +0 -147
  79. torio/io/__init__.py +0 -9
  80. torio/io/_streaming_media_decoder.py +0 -978
  81. torio/io/_streaming_media_encoder.py +0 -502
  82. torio/lib/__init__.py +0 -0
  83. torio/lib/_torio_ffmpeg4.pyd +0 -0
  84. torio/lib/_torio_ffmpeg5.pyd +0 -0
  85. torio/lib/_torio_ffmpeg6.pyd +0 -0
  86. torio/lib/libtorio_ffmpeg4.pyd +0 -0
  87. torio/lib/libtorio_ffmpeg5.pyd +0 -0
  88. torio/lib/libtorio_ffmpeg6.pyd +0 -0
  89. torio/utils/__init__.py +0 -4
  90. torio/utils/ffmpeg_utils.py +0 -247
  91. {torchaudio-2.7.1.dist-info → torchaudio-2.9.0.dist-info}/LICENSE +0 -0
  92. {torchaudio-2.7.1.dist-info → torchaudio-2.9.0.dist-info}/WHEEL +0 -0
@@ -1,433 +0,0 @@
1
- import warnings
2
- from typing import List, Optional, Union
3
-
4
- import torch
5
-
6
- from torchaudio.functional import fftconvolve
7
-
8
-
9
- def oscillator_bank(
10
- frequencies: torch.Tensor,
11
- amplitudes: torch.Tensor,
12
- sample_rate: float,
13
- reduction: str = "sum",
14
- dtype: Optional[torch.dtype] = torch.float64,
15
- ) -> torch.Tensor:
16
- """Synthesize waveform from the given instantaneous frequencies and amplitudes.
17
-
18
- .. devices:: CPU CUDA
19
-
20
- .. properties:: Autograd TorchScript
21
-
22
- Note:
23
- The phase information of the output waveform is found by taking the cumulative sum
24
- of the given instantaneous frequencies (``frequencies``).
25
- This incurs roundoff error when the data type does not have enough precision.
26
- Using ``torch.float64`` can work around this.
27
-
28
- The following figure shows the difference between ``torch.float32`` and
29
- ``torch.float64`` when generating a sin wave of constant frequency and amplitude
30
- with sample rate 8000 [Hz].
31
- Notice that ``torch.float32`` version shows artifacts that are not seen in
32
- ``torch.float64`` version.
33
-
34
- .. image:: https://download.pytorch.org/torchaudio/doc-assets/oscillator_precision.png
35
-
36
- Args:
37
- frequencies (Tensor): Sample-wise oscillator frequencies (Hz). Shape `(..., time, N)`.
38
- amplitudes (Tensor): Sample-wise oscillator amplitude. Shape: `(..., time, N)`.
39
- sample_rate (float): Sample rate
40
- reduction (str): Reduction to perform.
41
- Valid values are ``"sum"``, ``"mean"`` or ``"none"``. Default: ``"sum"``
42
- dtype (torch.dtype or None, optional): The data type on which cumulative sum operation is performed.
43
- Default: ``torch.float64``. Pass ``None`` to disable the casting.
44
-
45
- Returns:
46
- Tensor:
47
- The resulting waveform.
48
-
49
- If ``reduction`` is ``"none"``, then the shape is
50
- `(..., time, N)`, otherwise the shape is `(..., time)`.
51
- """
52
- if frequencies.shape != amplitudes.shape:
53
- raise ValueError(
54
- "The shapes of `frequencies` and `amplitudes` must match. "
55
- f"Found: {frequencies.shape} and {amplitudes.shape} respectively."
56
- )
57
- reductions = ["sum", "mean", "none"]
58
- if reduction not in reductions:
59
- raise ValueError(f"The value of reduction must be either {reductions}. Found: {reduction}")
60
-
61
- invalid = torch.abs(frequencies) >= sample_rate / 2
62
- if torch.any(invalid):
63
- warnings.warn(
64
- "Some frequencies are above nyquist frequency. "
65
- "Setting the corresponding amplitude to zero. "
66
- "This might cause numerically unstable gradient."
67
- )
68
- amplitudes = torch.where(invalid, 0.0, amplitudes)
69
-
70
- pi2 = 2.0 * torch.pi
71
- freqs = frequencies * pi2 / sample_rate % pi2
72
- phases = torch.cumsum(freqs, dim=-2, dtype=dtype)
73
- if dtype is not None and freqs.dtype != dtype:
74
- phases = phases.to(freqs.dtype)
75
-
76
- waveform = amplitudes * torch.sin(phases)
77
- if reduction == "sum":
78
- return waveform.sum(-1)
79
- if reduction == "mean":
80
- return waveform.mean(-1)
81
- return waveform
82
-
83
-
84
- def adsr_envelope(
85
- num_frames: int,
86
- *,
87
- attack: float = 0.0,
88
- hold: float = 0.0,
89
- decay: float = 0.0,
90
- sustain: float = 1.0,
91
- release: float = 0.0,
92
- n_decay: int = 2,
93
- dtype: Optional[torch.dtype] = None,
94
- device: Optional[torch.device] = None,
95
- ):
96
- """Generate ADSR Envelope
97
-
98
- .. devices:: CPU CUDA
99
-
100
- Args:
101
- num_frames (int): The number of output frames.
102
- attack (float, optional):
103
- The relative *time* it takes to reach the maximum level from
104
- the start. (Default: ``0.0``)
105
- hold (float, optional):
106
- The relative *time* the maximum level is held before
107
- it starts to decay. (Default: ``0.0``)
108
- decay (float, optional):
109
- The relative *time* it takes to sustain from
110
- the maximum level. (Default: ``0.0``)
111
- sustain (float, optional): The relative *level* at which
112
- the sound should sustain. (Default: ``1.0``)
113
-
114
- .. Note::
115
- The duration of sustain is derived as `1.0 - (The sum of attack, hold, decay and release)`.
116
-
117
- release (float, optional): The relative *time* it takes for the sound level to
118
- reach zero after the sustain. (Default: ``0.0``)
119
- n_decay (int, optional): The degree of polynomial decay. Default: ``2``.
120
- dtype (torch.dtype, optional): the desired data type of returned tensor.
121
- Default: if ``None``, uses a global default
122
- (see :py:func:`torch.set_default_tensor_type`).
123
- device (torch.device, optional): the desired device of returned tensor.
124
- Default: if ``None``, uses the current device for the default tensor type
125
- (see :py:func:`torch.set_default_tensor_type`).
126
- device will be the CPU for CPU tensor types and the current CUDA
127
- device for CUDA tensor types.
128
-
129
- Returns:
130
- Tensor: ADSR Envelope. Shape: `(num_frames, )`
131
-
132
- Example
133
- .. image:: https://download.pytorch.org/torchaudio/doc-assets/adsr_examples.png
134
-
135
- """
136
- if not 0 <= attack <= 1:
137
- raise ValueError(f"The value of `attack` must be within [0, 1]. Found: {attack}")
138
- if not 0 <= decay <= 1:
139
- raise ValueError(f"The value of `decay` must be within [0, 1]. Found: {decay}")
140
- if not 0 <= sustain <= 1:
141
- raise ValueError(f"The value of `sustain` must be within [0, 1]. Found: {sustain}")
142
- if not 0 <= hold <= 1:
143
- raise ValueError(f"The value of `hold` must be within [0, 1]. Found: {hold}")
144
- if not 0 <= release <= 1:
145
- raise ValueError(f"The value of `release` must be within [0, 1]. Found: {release}")
146
- if attack + decay + release + hold > 1:
147
- raise ValueError("The sum of `attack`, `hold`, `decay` and `release` must not exceed 1.")
148
-
149
- nframes = num_frames - 1
150
- num_a = int(nframes * attack)
151
- num_h = int(nframes * hold)
152
- num_d = int(nframes * decay)
153
- num_r = int(nframes * release)
154
-
155
- # Initialize with sustain
156
- out = torch.full((num_frames,), float(sustain), device=device, dtype=dtype)
157
-
158
- # attack
159
- if num_a > 0:
160
- torch.linspace(0.0, 1.0, num_a + 1, out=out[: num_a + 1])
161
-
162
- # hold
163
- if num_h > 0:
164
- out[num_a : num_a + num_h + 1] = 1.0
165
-
166
- # decay
167
- if num_d > 0:
168
- # Compute: sustain + (1.0 - sustain) * (linspace[1, 0] ** n_decay)
169
- i = num_a + num_h
170
- decay = out[i : i + num_d + 1]
171
- torch.linspace(1.0, 0.0, num_d + 1, out=decay)
172
- decay **= n_decay
173
- decay *= 1.0 - sustain
174
- decay += sustain
175
-
176
- # sustain is handled by initialization
177
-
178
- # release
179
- if num_r > 0:
180
- torch.linspace(sustain, 0, num_r + 1, out=out[-num_r - 1 :])
181
-
182
- return out
183
-
184
-
185
- def extend_pitch(
186
- base: torch.Tensor,
187
- pattern: Union[int, List[float], torch.Tensor],
188
- ):
189
- """Extend the given time series values with multipliers of them.
190
-
191
- .. devices:: CPU CUDA
192
-
193
- .. properties:: Autograd TorchScript
194
-
195
- Given a series of fundamental frequencies (pitch), this function appends
196
- its harmonic overtones or inharmonic partials.
197
-
198
- Args:
199
- base (torch.Tensor):
200
- Base time series, like fundamental frequencies (Hz). Shape: `(..., time, 1)`.
201
- pattern (int, list of floats or torch.Tensor):
202
- If ``int``, the number of pitch series after the operation.
203
- `pattern - 1` tones are added, so that the resulting Tensor contains
204
- up to `pattern`-th overtones of the given series.
205
-
206
- If list of float or ``torch.Tensor``, it must be one dimensional,
207
- representing the custom multiplier of the fundamental frequency.
208
-
209
- Returns:
210
- Tensor: Oscillator frequencies (Hz). Shape: `(..., time, num_tones)`.
211
-
212
- Example
213
- >>> # fundamental frequency
214
- >>> f0 = torch.linspace(1, 5, 5).unsqueeze(-1)
215
- >>> f0
216
- tensor([[1.],
217
- [2.],
218
- [3.],
219
- [4.],
220
- [5.]])
221
- >>> # Add harmonic overtones, up to 3rd.
222
- >>> f = extend_pitch(f0, 3)
223
- >>> f.shape
224
- torch.Size([5, 3])
225
- >>> f
226
- tensor([[ 1., 2., 3.],
227
- [ 2., 4., 6.],
228
- [ 3., 6., 9.],
229
- [ 4., 8., 12.],
230
- [ 5., 10., 15.]])
231
- >>> # Add custom (inharmonic) partials.
232
- >>> f = extend_pitch(f0, torch.tensor([1, 2.1, 3.3, 4.5]))
233
- >>> f.shape
234
- torch.Size([5, 4])
235
- >>> f
236
- tensor([[ 1.0000, 2.1000, 3.3000, 4.5000],
237
- [ 2.0000, 4.2000, 6.6000, 9.0000],
238
- [ 3.0000, 6.3000, 9.9000, 13.5000],
239
- [ 4.0000, 8.4000, 13.2000, 18.0000],
240
- [ 5.0000, 10.5000, 16.5000, 22.5000]])
241
- """
242
- if isinstance(pattern, torch.Tensor):
243
- mult = pattern
244
- elif isinstance(pattern, int):
245
- mult = torch.linspace(1.0, float(pattern), pattern, device=base.device, dtype=base.dtype)
246
- else:
247
- mult = torch.tensor(pattern, dtype=base.dtype, device=base.device)
248
- h_freq = base @ mult.unsqueeze(0)
249
- return h_freq
250
-
251
-
252
- def sinc_impulse_response(cutoff: torch.Tensor, window_size: int = 513, high_pass: bool = False):
253
- """Create windowed-sinc impulse response for given cutoff frequencies.
254
-
255
- .. devices:: CPU CUDA
256
-
257
- .. properties:: Autograd TorchScript
258
-
259
- Args:
260
- cutoff (Tensor): Cutoff frequencies for low-pass sinc filter.
261
-
262
- window_size (int, optional): Size of the Hamming window to apply. Must be odd.
263
- (Default: 513)
264
-
265
- high_pass (bool, optional):
266
- If ``True``, convert the resulting filter to high-pass.
267
- Otherwise low-pass filter is returned. Default: ``False``.
268
-
269
- Returns:
270
- Tensor: A series of impulse responses. Shape: `(..., window_size)`.
271
- """
272
- if window_size % 2 == 0:
273
- raise ValueError(f"`window_size` must be odd. Given: {window_size}")
274
-
275
- half = window_size // 2
276
- device, dtype = cutoff.device, cutoff.dtype
277
- idx = torch.linspace(-half, half, window_size, device=device, dtype=dtype)
278
-
279
- filt = torch.special.sinc(cutoff.unsqueeze(-1) * idx.unsqueeze(0))
280
- filt = filt * torch.hamming_window(window_size, device=device, dtype=dtype, periodic=False).unsqueeze(0)
281
- filt = filt / filt.sum(dim=-1, keepdim=True).abs()
282
-
283
- # High pass IR is obtained by subtracting low_pass IR from delta function.
284
- # https://courses.engr.illinois.edu/ece401/fa2020/slides/lec10.pdf
285
- if high_pass:
286
- filt = -filt
287
- filt[..., half] = 1.0 + filt[..., half]
288
- return filt
289
-
290
-
291
- def frequency_impulse_response(magnitudes):
292
- """Create filter from desired frequency response
293
-
294
- Args:
295
- magnitudes: The desired frequency responses. Shape: `(..., num_fft_bins)`
296
-
297
- Returns:
298
- Tensor: Impulse response. Shape `(..., 2 * (num_fft_bins - 1))`
299
- """
300
- if magnitudes.min() < 0.0:
301
- # Negative magnitude does not make sense but allowing so that autograd works
302
- # around 0.
303
- # Should we raise error?
304
- warnings.warn("The input frequency response should not contain negative values.")
305
- ir = torch.fft.fftshift(torch.fft.irfft(magnitudes), dim=-1)
306
- device, dtype = magnitudes.device, magnitudes.dtype
307
- window = torch.hann_window(ir.size(-1), periodic=False, device=device, dtype=dtype).expand_as(ir)
308
- return ir * window
309
-
310
-
311
- def _overlap_and_add(waveform, stride):
312
- num_frames, frame_size = waveform.shape[-2:]
313
- numel = (num_frames - 1) * stride + frame_size
314
- buffer = torch.zeros(waveform.shape[:-2] + (numel,), device=waveform.device, dtype=waveform.dtype)
315
- for i in range(num_frames):
316
- start = i * stride
317
- end = start + frame_size
318
- buffer[..., start:end] += waveform[..., i, :]
319
- return buffer
320
-
321
-
322
- def filter_waveform(waveform: torch.Tensor, kernels: torch.Tensor, delay_compensation: int = -1):
323
- """Applies filters along time axis of the given waveform.
324
-
325
- This function applies the given filters along time axis in the following manner:
326
-
327
- 1. Split the given waveform into chunks. The number of chunks is equal to the number of given filters.
328
- 2. Filter each chunk with corresponding filter.
329
- 3. Place the filtered chunks at the original indices while adding up the overlapping parts.
330
- 4. Crop the resulting waveform so that delay introduced by the filter is removed and its length
331
- matches that of the input waveform.
332
-
333
- The following figure illustrates this.
334
-
335
- .. image:: https://download.pytorch.org/torchaudio/doc-assets/filter_waveform.png
336
-
337
- .. note::
338
-
339
- If the number of filters is one, then the operation becomes stationary.
340
- i.e. the same filtering is applied across the time axis.
341
-
342
- Args:
343
- waveform (Tensor): Shape `(..., time)`.
344
- kernels (Tensor): Impulse responses.
345
- Valid inputs are 2D tensor with shape `(num_filters, filter_length)` or
346
- `(N+1)`-D tensor with shape `(..., num_filters, filter_length)`, where `N` is
347
- the dimension of waveform.
348
-
349
- In case of 2D input, the same set of filters is used across channels and batches.
350
- Otherwise, different sets of filters are applied. In this case, the shape of
351
- the first `N-1` dimensions of filters must match (or be broadcastable to) that of waveform.
352
-
353
- delay_compensation (int): Control how the waveform is cropped after full convolution.
354
- If the value is zero or positive, it is interpreted as the length of crop at the
355
- beginning of the waveform. The value cannot be larger than the size of filter kernel.
356
- Otherwise the initial crop is ``filter_size // 2``.
357
- When cropping happens, the waveform is also cropped from the end so that the
358
- length of the resulting waveform matches the input waveform.
359
-
360
- Returns:
361
- Tensor: `(..., time)`.
362
- """
363
- if kernels.ndim not in [2, waveform.ndim + 1]:
364
- raise ValueError(
365
- "`kernels` must be 2 or N+1 dimension where "
366
- f"N is the dimension of waveform. Found: {kernels.ndim} (N={waveform.ndim})"
367
- )
368
-
369
- num_filters, filter_size = kernels.shape[-2:]
370
- num_frames = waveform.size(-1)
371
-
372
- if delay_compensation > filter_size:
373
- raise ValueError(
374
- "When `delay_compenstation` is provided, it cannot be larger than the size of filters."
375
- f"Found: delay_compensation={delay_compensation}, filter_size={filter_size}"
376
- )
377
-
378
- # Transform waveform's time axis into (num_filters x chunk_length) with optional padding
379
- chunk_length = num_frames // num_filters
380
- if num_frames % num_filters > 0:
381
- chunk_length += 1
382
- num_pad = chunk_length * num_filters - num_frames
383
- waveform = torch.nn.functional.pad(waveform, [0, num_pad], "constant", 0)
384
- chunked = waveform.unfold(-1, chunk_length, chunk_length)
385
- assert chunked.numel() >= waveform.numel()
386
-
387
- # Broadcast kernels
388
- if waveform.ndim + 1 > kernels.ndim:
389
- expand_shape = waveform.shape[:-1] + kernels.shape
390
- kernels = kernels.expand(expand_shape)
391
-
392
- convolved = fftconvolve(chunked, kernels)
393
- restored = _overlap_and_add(convolved, chunk_length)
394
-
395
- # Trim in a way that the number of samples are same as input,
396
- # and the filter delay is compensated
397
- if delay_compensation >= 0:
398
- start = delay_compensation
399
- else:
400
- start = filter_size // 2
401
- num_crops = restored.size(-1) - num_frames
402
- end = num_crops - start
403
- result = restored[..., start:-end]
404
- return result
405
-
406
-
407
- def exp_sigmoid(
408
- input: torch.Tensor, exponent: float = 10.0, max_value: float = 2.0, threshold: float = 1e-7
409
- ) -> torch.Tensor:
410
- """Exponential Sigmoid pointwise nonlinearity.
411
- Implements the equation:
412
- ``max_value`` * sigmoid(``input``) ** (log(``exponent``)) + ``threshold``
413
-
414
- The output has a range of [``threshold``, ``max_value``].
415
- ``exponent`` controls the slope of the output.
416
-
417
- .. devices:: CPU CUDA
418
-
419
- Args:
420
- input (Tensor): Input Tensor
421
- exponent (float, optional): Exponent. Controls the slope of the output
422
- max_value (float, optional): Maximum value of the output
423
- threshold (float, optional): Minimum value of the output
424
-
425
- Returns:
426
- Tensor: Exponential Sigmoid output. Shape: same as input
427
-
428
- """
429
-
430
- return max_value * torch.pow(
431
- torch.nn.functional.sigmoid(input),
432
- torch.log(torch.tensor(exponent, device=input.device, dtype=input.dtype)),
433
- ) + torch.tensor(threshold, device=input.device, dtype=input.dtype)