1
0

mask.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. '''
  18. def subsequent_mask(
  19. size: int,
  20. device: torch.device = torch.device("cpu"),
  21. ) -> torch.Tensor:
  22. """Create mask for subsequent steps (size, size).
  23. This mask is used only in decoder which works in an auto-regressive mode.
  24. This means the current step could only do attention with its left steps.
  25. In encoder, fully attention is used when streaming is not necessary and
  26. the sequence is not long. In this case, no attention mask is needed.
  27. When streaming is need, chunk-based attention is used in encoder. See
  28. subsequent_chunk_mask for the chunk-based attention mask.
  29. Args:
  30. size (int): size of mask
  31. str device (str): "cpu" or "cuda" or torch.Tensor.device
  32. dtype (torch.device): result dtype
  33. Returns:
  34. torch.Tensor: mask
  35. Examples:
  36. >>> subsequent_mask(3)
  37. [[1, 0, 0],
  38. [1, 1, 0],
  39. [1, 1, 1]]
  40. """
  41. ret = torch.ones(size, size, device=device, dtype=torch.bool)
  42. return torch.tril(ret)
  43. '''
  44. def subsequent_mask(
  45. size: int,
  46. device: torch.device = torch.device("cpu"),
  47. ) -> torch.Tensor:
  48. """Create mask for subsequent steps (size, size).
  49. This mask is used only in decoder which works in an auto-regressive mode.
  50. This means the current step could only do attention with its left steps.
  51. In encoder, fully attention is used when streaming is not necessary and
  52. the sequence is not long. In this case, no attention mask is needed.
  53. When streaming is need, chunk-based attention is used in encoder. See
  54. subsequent_chunk_mask for the chunk-based attention mask.
  55. Args:
  56. size (int): size of mask
  57. str device (str): "cpu" or "cuda" or torch.Tensor.device
  58. dtype (torch.device): result dtype
  59. Returns:
  60. torch.Tensor: mask
  61. Examples:
  62. >>> subsequent_mask(3)
  63. [[1, 0, 0],
  64. [1, 1, 0],
  65. [1, 1, 1]]
  66. """
  67. arange = torch.arange(size, device=device)
  68. mask = arange.expand(size, size)
  69. arange = arange.unsqueeze(-1)
  70. mask = mask <= arange
  71. return mask
  72. def subsequent_chunk_mask(
  73. size: int,
  74. chunk_size: int,
  75. num_left_chunks: int = -1,
  76. device: torch.device = torch.device("cpu"),
  77. ) -> torch.Tensor:
  78. """Create mask for subsequent steps (size, size) with chunk size,
  79. this is for streaming encoder
  80. Args:
  81. size (int): size of mask
  82. chunk_size (int): size of chunk
  83. num_left_chunks (int): number of left chunks
  84. <0: use full chunk
  85. >=0: use num_left_chunks
  86. device (torch.device): "cpu" or "cuda" or torch.Tensor.device
  87. Returns:
  88. torch.Tensor: mask
  89. Examples:
  90. >>> subsequent_chunk_mask(4, 2)
  91. [[1, 1, 0, 0],
  92. [1, 1, 0, 0],
  93. [1, 1, 1, 1],
  94. [1, 1, 1, 1]]
  95. """
  96. ret = torch.zeros(size, size, device=device, dtype=torch.bool)
  97. for i in range(size):
  98. if num_left_chunks < 0:
  99. start = 0
  100. else:
  101. start = max((i // chunk_size - num_left_chunks) * chunk_size, 0)
  102. ending = min((i // chunk_size + 1) * chunk_size, size)
  103. ret[i, start:ending] = True
  104. return ret
  105. def add_optional_chunk_mask(xs: torch.Tensor,
  106. masks: torch.Tensor,
  107. use_dynamic_chunk: bool,
  108. use_dynamic_left_chunk: bool,
  109. decoding_chunk_size: int,
  110. static_chunk_size: int,
  111. num_decoding_left_chunks: int,
  112. enable_full_context: bool = True):
  113. """ Apply optional mask for encoder.
  114. Args:
  115. xs (torch.Tensor): padded input, (B, L, D), L for max length
  116. mask (torch.Tensor): mask for xs, (B, 1, L)
  117. use_dynamic_chunk (bool): whether to use dynamic chunk or not
  118. use_dynamic_left_chunk (bool): whether to use dynamic left chunk for
  119. training.
  120. decoding_chunk_size (int): decoding chunk size for dynamic chunk, it's
  121. 0: default for training, use random dynamic chunk.
  122. <0: for decoding, use full chunk.
  123. >0: for decoding, use fixed chunk size as set.
  124. static_chunk_size (int): chunk size for static chunk training/decoding
  125. if it's greater than 0, if use_dynamic_chunk is true,
  126. this parameter will be ignored
  127. num_decoding_left_chunks: number of left chunks, this is for decoding,
  128. the chunk size is decoding_chunk_size.
  129. >=0: use num_decoding_left_chunks
  130. <0: use all left chunks
  131. enable_full_context (bool):
  132. True: chunk size is either [1, 25] or full context(max_len)
  133. False: chunk size ~ U[1, 25]
  134. Returns:
  135. torch.Tensor: chunk mask of the input xs.
  136. """
  137. # Whether to use chunk mask or not
  138. if use_dynamic_chunk:
  139. max_len = xs.size(1)
  140. if decoding_chunk_size < 0:
  141. chunk_size = max_len
  142. num_left_chunks = -1
  143. elif decoding_chunk_size > 0:
  144. chunk_size = decoding_chunk_size
  145. num_left_chunks = num_decoding_left_chunks
  146. else:
  147. # chunk size is either [1, 25] or full context(max_len).
  148. # Since we use 4 times subsampling and allow up to 1s(100 frames)
  149. # delay, the maximum frame is 100 / 4 = 25.
  150. chunk_size = torch.randint(1, max_len, (1, )).item()
  151. num_left_chunks = -1
  152. if chunk_size > max_len // 2 and enable_full_context:
  153. chunk_size = max_len
  154. else:
  155. chunk_size = chunk_size % 25 + 1
  156. if use_dynamic_left_chunk:
  157. max_left_chunks = (max_len - 1) // chunk_size
  158. num_left_chunks = torch.randint(0, max_left_chunks,
  159. (1, )).item()
  160. chunk_masks = subsequent_chunk_mask(xs.size(1), chunk_size,
  161. num_left_chunks,
  162. xs.device) # (L, L)
  163. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  164. chunk_masks = masks & chunk_masks # (B, L, L)
  165. elif static_chunk_size > 0:
  166. num_left_chunks = num_decoding_left_chunks
  167. chunk_masks = subsequent_chunk_mask(xs.size(1), static_chunk_size,
  168. num_left_chunks,
  169. xs.device) # (L, L)
  170. chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
  171. chunk_masks = masks & chunk_masks # (B, L, L)
  172. else:
  173. chunk_masks = masks
  174. return chunk_masks
  175. def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor:
  176. """Make mask tensor containing indices of padded part.
  177. See description of make_non_pad_mask.
  178. Args:
  179. lengths (torch.Tensor): Batch of lengths (B,).
  180. Returns:
  181. torch.Tensor: Mask tensor containing indices of padded part.
  182. Examples:
  183. >>> lengths = [5, 3, 2]
  184. >>> make_pad_mask(lengths)
  185. masks = [[0, 0, 0, 0 ,0],
  186. [0, 0, 0, 1, 1],
  187. [0, 0, 1, 1, 1]]
  188. """
  189. batch_size = lengths.size(0)
  190. max_len = max_len if max_len > 0 else lengths.max().item()
  191. seq_range = torch.arange(0,
  192. max_len,
  193. dtype=torch.int64,
  194. device=lengths.device)
  195. seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
  196. seq_length_expand = lengths.unsqueeze(-1)
  197. mask = seq_range_expand >= seq_length_expand
  198. return mask