Source code for diffsptk.core.cdist
# ------------------------------------------------------------------------ #
# Copyright 2022 SPTK Working Group #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# ------------------------------------------------------------------------ #
import math
import torch
import torch.nn as nn
from ..misc.utils import is_in
[docs]class CepstralDistance(nn.Module):
"""See `this page <https://sp-nitech.github.io/sptk/latest/main/cdist.html>`_
for details.
Parameters
----------
full : bool [scalar]
If True, include the constant term in the distance calculation.
reduction : ['none', 'mean', 'batchmean', 'sum']
Reduction type.
eps : float >= 0 [scalar]
A small value to prevent NaN.
"""
def __init__(self, full=False, reduction="mean", eps=1e-8):
super(CepstralDistance, self).__init__()
self.full = full
self.reduction = reduction
self.eps = eps
assert is_in(self.reduction, ["none", "mean", "batchmean", "sum"])
assert 0 <= self.eps
if self.full:
self.const = 10 * math.sqrt(2) / math.log(10)
[docs] def forward(self, c1, c2):
"""Calculate cepstral distance between two inputs.
Parameters
----------
c1 : Tensor [shape=(..., M+1)]
Input cepstral coefficients.
c2 : Tensor [shape=(..., M+1)]
Target cepstral coefficients.
Returns
-------
dist : Tensor [shape=(...,) or scalar]
Cepstral distance.
Examples
--------
>>> c1 = torch.randn(2, 3)
tensor([[ 0.4296, 1.6517, -0.6022],
[-1.0464, -0.6088, -0.9274]])
>>> c2 = torch.randn(2, 3)
tensor([[ 1.6441, -0.6962, -0.2524],
[ 0.9344, 0.3965, 1.1494]])
>>> cdist = diffsptk.CepstralDistance()
>>> dist = cdist(c1,c2)
>>> dist
tensor(1.6551)
"""
dist = torch.sqrt(torch.square(c1[..., 1:] - c2[..., 1:]).sum(-1) + self.eps)
if self.reduction == "none":
dist = dist + 0
elif self.reduction == "sum":
dist = dist.sum()
elif self.reduction == "mean":
dist = dist.mean() / math.sqrt(c1.shape[-1] - 1)
elif self.reduction == "batchmean":
dist = dist.mean()
else:
raise RuntimeError
if self.full:
dist *= self.const
return dist