mask.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # Copyright (c) 2019 Shigeki Karita
  2. # 2020 Mobvoi Inc (Binbin Zhang)
  3. # 2024 Alibaba Inc (authors: Xiang Lyu)
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. import torch
  17. from cosyvoice.utils.file_utils import logging
  18. '''
  19. def subsequent_mask(
  20. size: int,
  21. device: torch.device = torch.device("cpu"),
  22. ) -> torch.Tensor:
  23. """Create mask for subsequent steps (size, size).
  24. This mask is used only in decoder which works in an auto-regressive mode.
  25. This means the current step could only do attention with its left steps.
  26. In encoder, fully attention is used when streaming is not necessary and
  27. the sequence is not long. In this case, no attention mask is needed.
  28. When streaming is need, chunk-based attention is used in encoder. See
  29. subsequent_chunk_mask for the chunk-based attention mask.
  30. Args:
  31. size (int): size of mask
  32. str device (str): "cpu" or "cuda" or torch.Tensor.device
  33. dtype (torch.device): result dtype
  34. Returns:
  35. torch.Tensor: mask
  36. Examples:
  37. >>> subsequent_mask(3)
  38. [[1, 0, 0],
  39. [1, 1, 0],
  40. [1, 1, 1]]
  41. """
  42. ret = torch.ones(size, size, device=device, dtype=torch.bool)
  43. return torch.tril(ret)
  44. '''
  45. def subsequent_mask(
  46. size: int,
  47. device: torch.device = torch.device("cpu"),
  48. ) -> torch.Tensor:
  49. """Create mask for subsequent steps (size, size).
  50. This mask is used only in decoder which works in an auto-regressive mode.
  51. This means the current step could only do attention with its left steps.
  52. In encoder, fully attention is used when streaming is not necessary and
  53. the sequence is not long. In this case, no attention mask is needed.
  54. When streaming is need, chunk-based attention is used in encoder. See
  55. subsequent_chunk_mask for the chunk-based attention mask.
  56. Args:
  57. size (int): size of mask
  58. str device (str): "cpu" or "cuda" or torch.Tensor.device
  59. dtype (torch.device): result dtype
  60. Returns:
  61. torch.Tensor: mask
  62. Examples:
  63. >>> subsequent_mask(3)
  64. [[1, 0, 0],
  65. [1, 1, 0],
  66. [1, 1, 1]]
  67. """
  68. arange = torch.arange(size, device=device)
  69. mask = arange.expand(size, size)
  70. arange = arange.unsqueeze(-1)
  71. mask = mask <= arange
  72. return mask
  73. def subsequent_chunk_mask(
  74. size: int,
  75. chunk_size: int,
  76. num_left_chunks: int = -1,
  77. device: torch.device = torch.device("cpu"),
  78. ) -> torch.Tensor:
  79. """Create mask for subsequent steps (size, size) with chunk size,
  80. this is for streaming encoder
  81. Args:
  82. size (int): size of mask
  83. chunk_size (int): size of chunk
  84. num_left_chunks (int): number of left chunks
  85. <0: use full chunk
  86. >=0: use num_left_chunks
  87. device (torch.device): "cpu" or "cuda" or torch.Tensor.device
  88. Returns:
  89. torch.Tensor: mask
  90. Examples:
  91. >>> subsequent_chunk_mask(4, 2)
  92. [[1, 1, 0, 0],
  93. [1, 1, 0, 0],
  94. [1, 1, 1, 1],
  95. [1, 1, 1, 1]]
  96. """
  97. ret = torch.zeros(size, size, device=device, dtype=torch.bool)
  98. for i in range(size):
  99. if num_left_chunks < 0:
  100. start = 0
  101. else:
  102. start = max((i // chunk_size - num_left_chunks) * chunk_size, 0)
  103. ending = min((i // chunk_size + 1) * chunk_size, size)
  104. ret[i, start:ending] = True
  105. return ret
  106. def add_optional_chunk_mask(xs: torch.Tensor,
  107. masks: torch.Tensor,
  108. use_dynamic_chunk: bool,
  109. use_dynamic_left_chunk: bool,
  110. decoding_chunk_size: int,
  111. static_chunk_size: int,
  112. num_decoding_left_chunks: int,
  113. enable_full_context: bool = True):
  114. """ Apply optional mask for encoder.
  115. Args:
  116. xs (torch.Tensor): padded input, (B, L, D), L for max length
  117. mask (torch.Tensor): mask for xs, (B, 1, L)
  118. use_dynamic_chunk (bool): whether to use dynamic chunk or not
  119. use_dynamic_left_chunk (bool): whether to use dynamic left chunk for
  120. training.
  121. decoding_chunk_size (int): decoding chunk size for dynamic chunk, it's
  122. 0: default for training, use random dynamic chunk.
  123. <0: for decoding, use full chunk.
  124. >0: for decoding, use fixed chunk size as set.
  125. static_chunk_size (int): chunk size for static chunk training/decoding
  126. if it's greater than 0, if use_dynamic_chunk is true,
  127. this parameter will be ignored
  128. num_decoding_left_chunks: number of left chunks, this is for decoding,
  129. the chunk size is decoding_chunk_size.
  130. >=0: use num_decoding_left_chunks
  131. <0: use all left chunks
  132. enable_full_context (bool):
  133. True: chunk size is either [1, 25] or full context(max_len)
  134. False: chunk size ~ U[1, 25]
  135. Returns:
  136. torch.Tensor: chunk mask of the input xs.
  137. """
  138. # Whether to use chunk mask or not
  139. if use_dynamic_chunk:
  140. max_len = xs.size(1)
  141. if decoding_chunk_size < 0:
  142. chunk_size = max_len
  143. num_left_chunks = -1
  144. elif decoding_chunk_size > 0:
  145. chunk_size = decoding_chunk_size
  146. num_left_chunks = num_decoding_left_chunks
  147. else:
  148. # chunk size is either [1, 25] or full context(max_len).
  149. # Since we use 4 times subsampling and allow up to 1s(100 frames)
  150. # delay, the maximum frame is 100 / 4 = 25.
  151. chunk_size = torch.randint(1, max_len, (1, )).item()
  152. num_left_chunks = -1
  153. if chunk_size > max_len // 2 and enable_full_context:
  154. chunk_size = max_len
  155. else:
  156. chunk_size = chunk_size % 25 + 1
  157. if use_dynamic_left_chunk:
  158. max_left_chunks = (max_len - 1) // chunk_size
  159. num_left_chunks = torch.randint(0, max_left_chunks,
  160. (1, )).item()
  161. chunk_masks = subsequent_chunk_mask(xs.size(1), chunk_size,
  162. num_left_chunks,
  163. xs.device) # (L, L)
  164. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  165. chunk_masks = masks & chunk_masks # (B, L, L)
  166. elif static_chunk_size > 0:
  167. num_left_chunks = num_decoding_left_chunks
  168. chunk_masks = subsequent_chunk_mask(xs.size(1), static_chunk_size,
  169. num_left_chunks,
  170. xs.device) # (L, L)
  171. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  172. chunk_masks = masks & chunk_masks # (B, L, L)
  173. else:
  174. chunk_masks = masks
  175. assert chunk_masks.dtype == torch.bool
  176. if (chunk_masks.sum(dim=-1) == 0).sum().item() != 0:
  177. logging.warning('get chunk_masks all false at some timestep, force set to true, make sure they are masked in futuer computation!')
  178. chunk_masks[chunk_masks.sum(dim=-1)==0] = True
  179. return chunk_masks
  180. def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor:
  181. """Make mask tensor containing indices of padded part.
  182. See description of make_non_pad_mask.
  183. Args:
  184. lengths (torch.Tensor): Batch of lengths (B,).
  185. Returns:
  186. torch.Tensor: Mask tensor containing indices of padded part.
  187. Examples:
  188. >>> lengths = [5, 3, 2]
  189. >>> make_pad_mask(lengths)
  190. masks = [[0, 0, 0, 0 ,0],
  191. [0, 0, 0, 1, 1],
  192. [0, 0, 1, 1, 1]]
  193. """
  194. batch_size = lengths.size(0)
  195. max_len = max_len if max_len > 0 else lengths.max().item()
  196. seq_range = torch.arange(0,
  197. max_len,
  198. dtype=torch.int64,
  199. device=lengths.device)
  200. seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
  201. seq_length_expand = lengths.unsqueeze(-1)
  202. mask = seq_range_expand >= seq_length_expand
  203. return mask