statistic_pooling.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import torch
  2. from typing import Tuple
  3. from typing import Union
  4. from funasr.modules.nets_utils import make_non_pad_mask
  5. from torch.nn import functional as F
  6. import math
  7. VAR2STD_EPSILON = 1e-12
  8. class StatisticPooling(torch.nn.Module):
  9. def __init__(self, pooling_dim: Union[int, Tuple] = 2, eps=1e-12):
  10. super(StatisticPooling, self).__init__()
  11. if isinstance(pooling_dim, int):
  12. pooling_dim = (pooling_dim, )
  13. self.pooling_dim = pooling_dim
  14. self.eps = eps
  15. def forward(self, xs_pad, ilens=None):
  16. # xs_pad in (Batch, Channel, Time, Frequency)
  17. if ilens is None:
  18. masks = torch.ones_like(xs_pad).to(xs_pad)
  19. else:
  20. masks = make_non_pad_mask(ilens, xs_pad, length_dim=2).to(xs_pad)
  21. mean = (torch.sum(xs_pad, dim=self.pooling_dim, keepdim=True) /
  22. torch.sum(masks, dim=self.pooling_dim, keepdim=True))
  23. squared_difference = torch.pow(xs_pad - mean, 2.0)
  24. variance = (torch.sum(squared_difference, dim=self.pooling_dim, keepdim=True) /
  25. torch.sum(masks, dim=self.pooling_dim, keepdim=True))
  26. for i in reversed(self.pooling_dim):
  27. mean, variance = torch.squeeze(mean, dim=i), torch.squeeze(variance, dim=i)
  28. mask = torch.less_equal(variance, self.eps).float()
  29. variance = (1.0 - mask) * variance + mask * self.eps
  30. stddev = torch.sqrt(variance)
  31. stat_pooling = torch.cat([mean, stddev], dim=1)
  32. return stat_pooling
  33. def convert_tf2torch(self, var_dict_tf, var_dict_torch):
  34. return {}
  35. def statistic_pooling(
  36. xs_pad: torch.Tensor,
  37. ilens: torch.Tensor = None,
  38. pooling_dim: Tuple = (2, 3)
  39. ) -> torch.Tensor:
  40. # xs_pad in (Batch, Channel, Time, Frequency)
  41. if ilens is None:
  42. seq_mask = torch.ones_like(xs_pad).to(xs_pad)
  43. else:
  44. seq_mask = make_non_pad_mask(ilens, xs_pad, length_dim=2).to(xs_pad)
  45. mean = (torch.sum(xs_pad, dim=pooling_dim, keepdim=True) /
  46. torch.sum(seq_mask, dim=pooling_dim, keepdim=True))
  47. squared_difference = torch.pow(xs_pad - mean, 2.0)
  48. variance = (torch.sum(squared_difference, dim=pooling_dim, keepdim=True) /
  49. torch.sum(seq_mask, dim=pooling_dim, keepdim=True))
  50. for i in reversed(pooling_dim):
  51. mean, variance = torch.squeeze(mean, dim=i), torch.squeeze(variance, dim=i)
  52. value_mask = torch.less_equal(variance, VAR2STD_EPSILON).float()
  53. variance = (1.0 - value_mask) * variance + value_mask * VAR2STD_EPSILON
  54. stddev = torch.sqrt(variance)
  55. stat_pooling = torch.cat([mean, stddev], dim=1)
  56. return stat_pooling
  57. def windowed_statistic_pooling(
  58. xs_pad: torch.Tensor,
  59. ilens: torch.Tensor = None,
  60. pooling_dim: Tuple = (2, 3),
  61. pooling_size: int = 20,
  62. pooling_stride: int = 1
  63. ) -> Tuple[torch.Tensor, int]:
  64. # xs_pad in (Batch, Channel, Time, Frequency)
  65. tt = xs_pad.shape[2]
  66. num_chunk = int(math.ceil(tt / pooling_stride))
  67. pad = pooling_size // 2
  68. if len(xs_pad.shape) == 4:
  69. features = F.pad(xs_pad, (0, 0, pad, pad), "replicate")
  70. else:
  71. features = F.pad(xs_pad, (pad, pad), "replicate")
  72. stat_list = []
  73. for i in range(num_chunk):
  74. # B x C
  75. st, ed = i*pooling_stride, i*pooling_stride+pooling_size
  76. stat = statistic_pooling(features[:, :, st: ed], pooling_dim=pooling_dim)
  77. stat_list.append(stat.unsqueeze(2))
  78. # B x C x T
  79. return torch.cat(stat_list, dim=2), ilens / pooling_stride