mask.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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_deprecated(
  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 subsequent_chunk_mask(
  107. size: int,
  108. chunk_size: int,
  109. num_left_chunks: int = -1,
  110. device: torch.device = torch.device("cpu"),
  111. ) -> torch.Tensor:
  112. """Create mask for subsequent steps (size, size) with chunk size,
  113. this is for streaming encoder
  114. Args:
  115. size (int): size of mask
  116. chunk_size (int): size of chunk
  117. num_left_chunks (int): number of left chunks
  118. <0: use full chunk
  119. >=0: use num_left_chunks
  120. device (torch.device): "cpu" or "cuda" or torch.Tensor.device
  121. Returns:
  122. torch.Tensor: mask
  123. Examples:
  124. >>> subsequent_chunk_mask(4, 2)
  125. [[1, 1, 0, 0],
  126. [1, 1, 0, 0],
  127. [1, 1, 1, 1],
  128. [1, 1, 1, 1]]
  129. """
  130. # NOTE this modified implementation meets onnx export requirements, but it doesn't support num_left_chunks
  131. # actually this is not needed after we have inference cache implemented, will remove it later
  132. pos_idx = torch.arange(size, device=device)
  133. block_value = (torch.div(pos_idx, chunk_size, rounding_mode='trunc') + 1) * chunk_size
  134. ret = pos_idx.unsqueeze(0) < block_value.unsqueeze(1)
  135. return ret
  136. def add_optional_chunk_mask(xs: torch.Tensor,
  137. masks: torch.Tensor,
  138. use_dynamic_chunk: bool,
  139. use_dynamic_left_chunk: bool,
  140. decoding_chunk_size: int,
  141. static_chunk_size: int,
  142. num_decoding_left_chunks: int,
  143. enable_full_context: bool = True):
  144. """ Apply optional mask for encoder.
  145. Args:
  146. xs (torch.Tensor): padded input, (B, L, D), L for max length
  147. mask (torch.Tensor): mask for xs, (B, 1, L)
  148. use_dynamic_chunk (bool): whether to use dynamic chunk or not
  149. use_dynamic_left_chunk (bool): whether to use dynamic left chunk for
  150. training.
  151. decoding_chunk_size (int): decoding chunk size for dynamic chunk, it's
  152. 0: default for training, use random dynamic chunk.
  153. <0: for decoding, use full chunk.
  154. >0: for decoding, use fixed chunk size as set.
  155. static_chunk_size (int): chunk size for static chunk training/decoding
  156. if it's greater than 0, if use_dynamic_chunk is true,
  157. this parameter will be ignored
  158. num_decoding_left_chunks: number of left chunks, this is for decoding,
  159. the chunk size is decoding_chunk_size.
  160. >=0: use num_decoding_left_chunks
  161. <0: use all left chunks
  162. enable_full_context (bool):
  163. True: chunk size is either [1, 25] or full context(max_len)
  164. False: chunk size ~ U[1, 25]
  165. Returns:
  166. torch.Tensor: chunk mask of the input xs.
  167. """
  168. # Whether to use chunk mask or not
  169. if use_dynamic_chunk:
  170. max_len = xs.size(1)
  171. if decoding_chunk_size < 0:
  172. chunk_size = max_len
  173. num_left_chunks = -1
  174. elif decoding_chunk_size > 0:
  175. chunk_size = decoding_chunk_size
  176. num_left_chunks = num_decoding_left_chunks
  177. else:
  178. # chunk size is either [1, 25] or full context(max_len).
  179. # Since we use 4 times subsampling and allow up to 1s(100 frames)
  180. # delay, the maximum frame is 100 / 4 = 25.
  181. chunk_size = torch.randint(1, max_len, (1, )).item()
  182. num_left_chunks = -1
  183. if chunk_size > max_len // 2 and enable_full_context:
  184. chunk_size = max_len
  185. else:
  186. chunk_size = chunk_size % 25 + 1
  187. if use_dynamic_left_chunk:
  188. max_left_chunks = (max_len - 1) // chunk_size
  189. num_left_chunks = torch.randint(0, max_left_chunks,
  190. (1, )).item()
  191. chunk_masks = subsequent_chunk_mask(xs.size(1), chunk_size,
  192. num_left_chunks,
  193. xs.device) # (L, L)
  194. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  195. chunk_masks = masks & chunk_masks # (B, L, L)
  196. elif static_chunk_size > 0:
  197. num_left_chunks = num_decoding_left_chunks
  198. chunk_masks = subsequent_chunk_mask(xs.size(1), static_chunk_size,
  199. num_left_chunks,
  200. xs.device) # (L, L)
  201. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  202. chunk_masks = masks & chunk_masks # (B, L, L)
  203. else:
  204. chunk_masks = masks
  205. assert chunk_masks.dtype == torch.bool
  206. if (chunk_masks.sum(dim=-1) == 0).sum().item() != 0:
  207. logging.warning('get chunk_masks all false at some timestep, force set to true, make sure they are masked in futuer computation!')
  208. chunk_masks[chunk_masks.sum(dim=-1)==0] = True
  209. return chunk_masks
  210. def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor:
  211. """Make mask tensor containing indices of padded part.
  212. See description of make_non_pad_mask.
  213. Args:
  214. lengths (torch.Tensor): Batch of lengths (B,).
  215. Returns:
  216. torch.Tensor: Mask tensor containing indices of padded part.
  217. Examples:
  218. >>> lengths = [5, 3, 2]
  219. >>> make_pad_mask(lengths)
  220. masks = [[0, 0, 0, 0 ,0],
  221. [0, 0, 0, 1, 1],
  222. [0, 0, 1, 1, 1]]
  223. """
  224. batch_size = lengths.size(0)
  225. max_len = max_len if max_len > 0 else lengths.max().item()
  226. seq_range = torch.arange(0,
  227. max_len,
  228. dtype=torch.int64,
  229. device=lengths.device)
  230. seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
  231. seq_length_expand = lengths.unsqueeze(-1)
  232. mask = seq_range_expand >= seq_length_expand
  233. return mask