Source code for diffsptk.modules.mlpg

# ------------------------------------------------------------------------ #
# 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 torch
import torch.nn as nn

from ..misc.utils import check_size
from ..misc.utils import to
from .delta import Delta


[docs] class MaximumLikelihoodParameterGeneration(nn.Module): """See `this page <https://sp-nitech.github.io/sptk/latest/main/mlpg.html>`_ for details. Currently, only global unit variance is supported. Parameters ---------- size : int >= 1 Length of input, :math:`T`. seed : list[list[float]] or list[int] Delta coefficients or width(s) of 1st (and 2nd) regression coefficients. """ def __init__(self, size, seed=[[-0.5, 0, 0.5], [1, -2, 1]]): super(MaximumLikelihoodParameterGeneration, self).__init__() assert 1 <= size self.size = size self.register_buffer("M", self._precompute(size, seed))
[docs] def forward(self, u): """Perform MLPG to obtain smoothed static sequence. Parameters ---------- u : Tensor [shape=(..., T, DxH)] Time-variant mean vectors with delta components. Returns ------- out : Tensor [shape=(..., T, D)] Static components. Examples -------- >>> x = diffsptk.ramp(1, 8).view(1, -1, 2) >>> x tensor([[[1., 2.], [3., 4.], [5., 6.], [7., 8.]]]) >>> delta = diffsptk.Delta([[-0.5, 0], [0, 0, 0.5]]) >>> y = delta(x) >>> y tensor([[[ 1.0000, 2.0000, -0.5000, -1.0000, 1.5000, 2.0000], [ 3.0000, 4.0000, -0.5000, -1.0000, 2.5000, 3.0000], [ 5.0000, 6.0000, -1.5000, -2.0000, 3.5000, 4.0000], [ 7.0000, 8.0000, -2.5000, -3.0000, 3.5000, 4.0000]]]) >>> mlpg = diffsptk.MLPG(y.size(1), [[-0.5, 0], [0, 0, 0.5]]) >>> c = mlpg(y) >>> c tensor([[[1., 2.], [3., 4.], [5., 6.], [7., 8.]]]) """ check_size(u.size(-2), self.size, "length of input") return self._forward(u, self.M)
@staticmethod def _forward(mean, M): T = mean.size(-2) H = M.size(-1) // T u = mean.reshape(*mean.shape[:-2], T * H, -1) c = torch.einsum("...Td,tT->...td", u, M) return c @staticmethod def _func(u, seed): M = MaximumLikelihoodParameterGeneration._precompute( u.size(-2), seed, dtype=u.dtype, device=u.device ) return MaximumLikelihoodParameterGeneration._forward(u, M) @staticmethod def _precompute(size, seed, dtype=None, device=None): # Make window. window = Delta._precompute(seed, True, dtype=torch.double, device=device) # Compute threshold. if isinstance(seed[0], (tuple, list)): th = [0] + [len(coefficients) // 2 for coefficients in seed] else: th = [0] + list(seed) th = torch.tensor(th, dtype=torch.double, device=device).unsqueeze(1) H, L = window.shape N = (L - 1) // 2 T = size W = torch.zeros((T * H, T), dtype=torch.double, device=device) # Make window matrix for t in range(T): hs = H * t he = hs + H ts = t - N te = ts + L if ts < 0: W[hs:he, :te] = window[:, -ts:] * (th <= t) elif T < te: W[hs:he, ts:] = window[:, : T - ts] * (th < T - t) else: W[hs:he, ts:te] = window WS = W.T # Assume unit variance. WSW = torch.matmul(WS, W) WSW = torch.linalg.inv(WSW) M = torch.matmul(WSW, WS) # (T, TxH) return to(M, dtype=dtype)