flow_matching.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du)
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import torch
  15. import torch.nn.functional as F
  16. from matcha.models.components.flow_matching import BASECFM
  17. class ConditionalCFM(BASECFM):
  18. def __init__(self, in_channels, cfm_params, n_spks=1, spk_emb_dim=64, estimator: torch.nn.Module = None):
  19. super().__init__(
  20. n_feats=in_channels,
  21. cfm_params=cfm_params,
  22. n_spks=n_spks,
  23. spk_emb_dim=spk_emb_dim,
  24. )
  25. self.t_scheduler = cfm_params.t_scheduler
  26. self.training_cfg_rate = cfm_params.training_cfg_rate
  27. self.inference_cfg_rate = cfm_params.inference_cfg_rate
  28. in_channels = in_channels + (spk_emb_dim if n_spks > 0 else 0)
  29. # Just change the architecture of the estimator here
  30. self.estimator = estimator
  31. @torch.inference_mode()
  32. def forward(self, mu, mask, n_timesteps, temperature=1.0, spks=None, cond=None, prompt_len=0, flow_cache=torch.zeros(1, 80, 0, 2)):
  33. """Forward diffusion
  34. Args:
  35. mu (torch.Tensor): output of encoder
  36. shape: (batch_size, n_feats, mel_timesteps)
  37. mask (torch.Tensor): output_mask
  38. shape: (batch_size, 1, mel_timesteps)
  39. n_timesteps (int): number of diffusion steps
  40. temperature (float, optional): temperature for scaling noise. Defaults to 1.0.
  41. spks (torch.Tensor, optional): speaker ids. Defaults to None.
  42. shape: (batch_size, spk_emb_dim)
  43. cond: Not used but kept for future purposes
  44. Returns:
  45. sample: generated mel-spectrogram
  46. shape: (batch_size, n_feats, mel_timesteps)
  47. """
  48. z = torch.randn_like(mu) * temperature
  49. cache_size = flow_cache.shape[2]
  50. # fix prompt and overlap part mu and z
  51. if cache_size != 0:
  52. z[:, :, :cache_size] = flow_cache[:, :, :, 0]
  53. mu[:, :, :cache_size] = flow_cache[:, :, :, 1]
  54. z_cache = torch.concat([z[:, :, :prompt_len], z[:, :, -34:]], dim=2)
  55. mu_cache = torch.concat([mu[:, :, :prompt_len], mu[:, :, -34:]], dim=2)
  56. flow_cache = torch.stack([z_cache, mu_cache], dim=-1)
  57. t_span = torch.linspace(0, 1, n_timesteps + 1, device=mu.device, dtype=mu.dtype)
  58. if self.t_scheduler == 'cosine':
  59. t_span = 1 - torch.cos(t_span * 0.5 * torch.pi)
  60. return self.solve_euler(z, t_span=t_span, mu=mu, mask=mask, spks=spks, cond=cond), flow_cache
  61. def solve_euler(self, x, t_span, mu, mask, spks, cond):
  62. """
  63. Fixed euler solver for ODEs.
  64. Args:
  65. x (torch.Tensor): random noise
  66. t_span (torch.Tensor): n_timesteps interpolated
  67. shape: (n_timesteps + 1,)
  68. mu (torch.Tensor): output of encoder
  69. shape: (batch_size, n_feats, mel_timesteps)
  70. mask (torch.Tensor): output_mask
  71. shape: (batch_size, 1, mel_timesteps)
  72. spks (torch.Tensor, optional): speaker ids. Defaults to None.
  73. shape: (batch_size, spk_emb_dim)
  74. cond: Not used but kept for future purposes
  75. """
  76. t, _, dt = t_span[0], t_span[-1], t_span[1] - t_span[0]
  77. t = t.unsqueeze(dim=0)
  78. # I am storing this because I can later plot it by putting a debugger here and saving it to a file
  79. # Or in future might add like a return_all_steps flag
  80. sol = []
  81. for step in range(1, len(t_span)):
  82. # Classifier-Free Guidance inference introduced in VoiceBox
  83. if self.inference_cfg_rate > 0:
  84. x_in = torch.concat([x, x], dim=0)
  85. mask_in = torch.concat([mask, mask], dim=0)
  86. mu_in = torch.concat([mu, torch.zeros_like(mu).to(x.device)], dim=0)
  87. t_in = torch.concat([t, t], dim=0)
  88. spks_in = torch.concat([spks, torch.zeros_like(spks).to(x.device)], dim=0) if spks is not None else None
  89. cond_in = torch.concat([cond, torch.zeros_like(cond).to(x.device)], dim=0) if cond is not None else None
  90. else:
  91. x_in, mask_in, mu_in, t_in, spks_in, cond_in = x, mask, mu, t, spks, cond
  92. dphi_dt = self.forward_estimator(
  93. x_in, mask_in,
  94. mu_in, t_in,
  95. spks_in,
  96. cond_in
  97. )
  98. if self.inference_cfg_rate > 0:
  99. dphi_dt, cfg_dphi_dt = torch.split(dphi_dt, [x.size(0), x.size(0)], dim=0)
  100. dphi_dt = ((1.0 + self.inference_cfg_rate) * dphi_dt - self.inference_cfg_rate * cfg_dphi_dt)
  101. x = x + dt * dphi_dt
  102. t = t + dt
  103. sol.append(x)
  104. if step < len(t_span) - 1:
  105. dt = t_span[step + 1] - t
  106. return sol[-1]
  107. def forward_estimator(self, x, mask, mu, t, spks, cond):
  108. if isinstance(self.estimator, torch.nn.Module):
  109. return self.estimator.forward(x, mask, mu, t, spks, cond)
  110. else:
  111. ort_inputs = {
  112. 'x': x.cpu().numpy(),
  113. 'mask': mask.cpu().numpy(),
  114. 'mu': mu.cpu().numpy(),
  115. 't': t.cpu().numpy(),
  116. 'spks': spks.cpu().numpy(),
  117. 'cond': cond.cpu().numpy()
  118. }
  119. output = self.estimator.run(None, ort_inputs)[0]
  120. return torch.tensor(output, dtype=x.dtype, device=x.device)
  121. def compute_loss(self, x1, mask, mu, spks=None, cond=None):
  122. """Computes diffusion loss
  123. Args:
  124. x1 (torch.Tensor): Target
  125. shape: (batch_size, n_feats, mel_timesteps)
  126. mask (torch.Tensor): target mask
  127. shape: (batch_size, 1, mel_timesteps)
  128. mu (torch.Tensor): output of encoder
  129. shape: (batch_size, n_feats, mel_timesteps)
  130. spks (torch.Tensor, optional): speaker embedding. Defaults to None.
  131. shape: (batch_size, spk_emb_dim)
  132. Returns:
  133. loss: conditional flow matching loss
  134. y: conditional flow
  135. shape: (batch_size, n_feats, mel_timesteps)
  136. """
  137. b, _, t = mu.shape
  138. # random timestep
  139. t = torch.rand([b, 1, 1], device=mu.device, dtype=mu.dtype)
  140. if self.t_scheduler == 'cosine':
  141. t = 1 - torch.cos(t * 0.5 * torch.pi)
  142. # sample noise p(x_0)
  143. z = torch.randn_like(x1)
  144. y = (1 - (1 - self.sigma_min) * t) * z + t * x1
  145. u = x1 - (1 - self.sigma_min) * z
  146. # during training, we randomly drop condition to trade off mode coverage and sample fidelity
  147. if self.training_cfg_rate > 0:
  148. cfg_mask = torch.rand(b, device=x1.device) > self.training_cfg_rate
  149. mu = mu * cfg_mask.view(-1, 1, 1)
  150. spks = spks * cfg_mask.view(-1, 1)
  151. cond = cond * cfg_mask.view(-1, 1, 1)
  152. pred = self.estimator(y, mask, mu, t.squeeze(), spks, cond)
  153. loss = F.mse_loss(pred * mask, u * mask, reduction="sum") / (torch.sum(mask) * u.shape[1])
  154. return loss, y
  155. class CausalConditionalCFM(ConditionalCFM):
  156. def __init__(self, in_channels, cfm_params, n_spks=1, spk_emb_dim=64, estimator: torch.nn.Module = None):
  157. super().__init__(in_channels, cfm_params, n_spks, spk_emb_dim, estimator)
  158. self.rand_noise = torch.randn([1, 80, 50 * 300])
  159. @torch.inference_mode()
  160. def forward(self, mu, mask, n_timesteps, temperature=1.0, spks=None, cond=None):
  161. """Forward diffusion
  162. Args:
  163. mu (torch.Tensor): output of encoder
  164. shape: (batch_size, n_feats, mel_timesteps)
  165. mask (torch.Tensor): output_mask
  166. shape: (batch_size, 1, mel_timesteps)
  167. n_timesteps (int): number of diffusion steps
  168. temperature (float, optional): temperature for scaling noise. Defaults to 1.0.
  169. spks (torch.Tensor, optional): speaker ids. Defaults to None.
  170. shape: (batch_size, spk_emb_dim)
  171. cond: Not used but kept for future purposes
  172. Returns:
  173. sample: generated mel-spectrogram
  174. shape: (batch_size, n_feats, mel_timesteps)
  175. """
  176. z = self.rand_noise[:, :, :mu.size(2)].to(mu.device) * temperature
  177. z[:] = 0
  178. # fix prompt and overlap part mu and z
  179. t_span = torch.linspace(0, 1, n_timesteps + 1, device=mu.device, dtype=mu.dtype)
  180. if self.t_scheduler == 'cosine':
  181. t_span = 1 - torch.cos(t_span * 0.5 * torch.pi)
  182. return self.solve_euler(z, t_span=t_span, mu=mu, mask=mask, spks=spks, cond=cond), None