lit_module.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. import itertools
  2. from typing import Any, Callable
  3. import lightning as L
  4. import torch
  5. import torch.nn.functional as F
  6. import wandb
  7. from lightning.pytorch.loggers import TensorBoardLogger, WandbLogger
  8. from matplotlib import pyplot as plt
  9. from torch import nn
  10. from vector_quantize_pytorch import VectorQuantize
  11. from fish_speech.models.vqgan.losses import (
  12. discriminator_loss,
  13. feature_loss,
  14. generator_loss,
  15. kl_loss,
  16. )
  17. from fish_speech.models.vqgan.modules.decoder import Generator
  18. from fish_speech.models.vqgan.modules.discriminator import EnsembleDiscriminator
  19. from fish_speech.models.vqgan.modules.encoders import (
  20. ConvDownSampler,
  21. SpeakerEncoder,
  22. TextEncoder,
  23. VQEncoder,
  24. )
  25. from fish_speech.models.vqgan.utils import (
  26. plot_mel,
  27. rand_slice_segments,
  28. sequence_mask,
  29. slice_segments,
  30. )
  31. class VQGAN(L.LightningModule):
  32. def __init__(
  33. self,
  34. optimizer: Callable,
  35. lr_scheduler: Callable,
  36. downsample: ConvDownSampler,
  37. vq_encoder: VQEncoder,
  38. mel_encoder: TextEncoder,
  39. decoder: TextEncoder,
  40. generator: Generator,
  41. discriminator: EnsembleDiscriminator,
  42. mel_transform: nn.Module,
  43. segment_size: int = 20480,
  44. hop_length: int = 640,
  45. sample_rate: int = 32000,
  46. freeze_hifigan: bool = False,
  47. freeze_vq: bool = False,
  48. speaker_encoder: SpeakerEncoder = None,
  49. ):
  50. super().__init__()
  51. # Model parameters
  52. self.optimizer_builder = optimizer
  53. self.lr_scheduler_builder = lr_scheduler
  54. # Generator and discriminators
  55. self.downsample = downsample
  56. self.vq_encoder = vq_encoder
  57. self.mel_encoder = mel_encoder
  58. self.speaker_encoder = speaker_encoder
  59. self.decoder = decoder
  60. self.generator = generator
  61. self.discriminator = discriminator
  62. self.mel_transform = mel_transform
  63. # Crop length for saving memory
  64. self.segment_size = segment_size
  65. self.hop_length = hop_length
  66. self.sampling_rate = sample_rate
  67. self.freeze_hifigan = freeze_hifigan
  68. self.freeze_vq = freeze_vq
  69. # Disable automatic optimization
  70. self.automatic_optimization = False
  71. # Stage 1: Train the VQ only
  72. if self.freeze_hifigan:
  73. for p in self.discriminator.parameters():
  74. p.requires_grad = False
  75. for p in self.generator.parameters():
  76. p.requires_grad = False
  77. # Stage 2: Train the HifiGAN + Decoder + Generator
  78. if freeze_vq:
  79. for p in self.vq_encoder.parameters():
  80. p.requires_grad = False
  81. for p in self.mel_encoder.parameters():
  82. p.requires_grad = False
  83. for p in self.downsample.parameters():
  84. p.requires_grad = False
  85. def configure_optimizers(self):
  86. # Need two optimizers and two schedulers
  87. components = []
  88. if self.freeze_vq is False:
  89. components.extend(
  90. [
  91. self.downsample.parameters(),
  92. self.vq_encoder.parameters(),
  93. self.mel_encoder.parameters(),
  94. ]
  95. )
  96. if self.speaker_encoder is not None:
  97. components.append(self.speaker_encoder.parameters())
  98. if self.decoder is not None:
  99. components.append(self.decoder.parameters())
  100. if self.freeze_hifigan is False:
  101. components.append(self.generator.parameters())
  102. optimizer_generator = self.optimizer_builder(itertools.chain(*components))
  103. optimizer_discriminator = self.optimizer_builder(
  104. self.discriminator.parameters()
  105. )
  106. lr_scheduler_generator = self.lr_scheduler_builder(optimizer_generator)
  107. lr_scheduler_discriminator = self.lr_scheduler_builder(optimizer_discriminator)
  108. return (
  109. {
  110. "optimizer": optimizer_generator,
  111. "lr_scheduler": {
  112. "scheduler": lr_scheduler_generator,
  113. "interval": "step",
  114. "name": "optimizer/generator",
  115. },
  116. },
  117. {
  118. "optimizer": optimizer_discriminator,
  119. "lr_scheduler": {
  120. "scheduler": lr_scheduler_discriminator,
  121. "interval": "step",
  122. "name": "optimizer/discriminator",
  123. },
  124. },
  125. )
  126. def training_step(self, batch, batch_idx):
  127. optim_g, optim_d = self.optimizers()
  128. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  129. audios = audios.float()
  130. audios = audios[:, None, :]
  131. with torch.no_grad():
  132. features = gt_mels = self.mel_transform(
  133. audios, sample_rate=self.sampling_rate
  134. )
  135. if self.freeze_vq:
  136. # Disable gradient computation for VQ
  137. torch.set_grad_enabled(False)
  138. self.vq_encoder.eval()
  139. self.mel_encoder.eval()
  140. self.downsample.eval()
  141. if self.downsample is not None:
  142. features = self.downsample(features)
  143. mel_lengths = audio_lengths // self.hop_length
  144. feature_lengths = (
  145. audio_lengths
  146. / self.hop_length
  147. / (self.downsample.total_strides if self.downsample is not None else 1)
  148. ).long()
  149. feature_masks = torch.unsqueeze(
  150. sequence_mask(feature_lengths, features.shape[2]), 1
  151. ).to(gt_mels.dtype)
  152. mel_masks = torch.unsqueeze(sequence_mask(mel_lengths, gt_mels.shape[2]), 1).to(
  153. gt_mels.dtype
  154. )
  155. # vq_features is 50 hz, need to convert to true mel size
  156. text_features = self.mel_encoder(features, feature_masks)
  157. text_features, _, loss_vq = self.vq_encoder(
  158. text_features, feature_masks, freeze_codebook=self.freeze_vq
  159. )
  160. text_features = F.interpolate(
  161. text_features, size=gt_mels.shape[2], mode="nearest"
  162. )
  163. if loss_vq.ndim > 1:
  164. loss_vq = loss_vq.mean()
  165. if self.freeze_vq:
  166. # Enable gradient computation
  167. torch.set_grad_enabled(True)
  168. # Sample mels
  169. if self.decoder is not None:
  170. speaker_features = (
  171. self.speaker_encoder(gt_mels, mel_masks)
  172. if self.speaker_encoder is not None
  173. else None
  174. )
  175. decoded_mels = self.decoder(text_features, mel_masks, g=speaker_features)
  176. else:
  177. decoded_mels = text_features
  178. fake_audios = self.generator(decoded_mels)
  179. y_hat_mels = self.mel_transform(fake_audios.squeeze(1))
  180. y, ids_slice = rand_slice_segments(audios, audio_lengths, self.segment_size)
  181. y_hat = slice_segments(fake_audios, ids_slice, self.segment_size)
  182. assert y.shape == y_hat.shape, f"{y.shape} != {y_hat.shape}"
  183. # Since we don't want to update the discriminator, we skip the backward pass
  184. if self.freeze_hifigan is False:
  185. # Discriminator
  186. y_d_hat_r, y_d_hat_g, _, _ = self.discriminator(y, y_hat.detach())
  187. with torch.autocast(device_type=audios.device.type, enabled=False):
  188. loss_disc_all, _, _ = discriminator_loss(y_d_hat_r, y_d_hat_g)
  189. self.log(
  190. "train/discriminator/loss",
  191. loss_disc_all,
  192. on_step=True,
  193. on_epoch=False,
  194. prog_bar=True,
  195. logger=True,
  196. sync_dist=True,
  197. )
  198. optim_d.zero_grad()
  199. self.manual_backward(loss_disc_all)
  200. self.clip_gradients(
  201. optim_d, gradient_clip_val=1.0, gradient_clip_algorithm="norm"
  202. )
  203. optim_d.step()
  204. y_d_hat_r, y_d_hat_g, fmap_r, fmap_g = self.discriminator(y, y_hat)
  205. with torch.autocast(device_type=audios.device.type, enabled=False):
  206. loss_decoded_mel = F.l1_loss(gt_mels * mel_masks, decoded_mels * mel_masks)
  207. loss_mel = F.l1_loss(gt_mels * mel_masks, y_hat_mels * mel_masks)
  208. loss_adv, _ = generator_loss(y_d_hat_g)
  209. loss_fm = feature_loss(fmap_r, fmap_g)
  210. if self.freeze_hifigan is True:
  211. loss_gen_all = loss_decoded_mel + loss_vq
  212. else:
  213. loss_gen_all = loss_mel * 45 + loss_vq * 45 + loss_fm + loss_adv
  214. self.log(
  215. "train/generator/loss",
  216. loss_gen_all,
  217. on_step=True,
  218. on_epoch=False,
  219. prog_bar=True,
  220. logger=True,
  221. sync_dist=True,
  222. )
  223. self.log(
  224. "train/generator/loss_decoded_mel",
  225. loss_decoded_mel,
  226. on_step=True,
  227. on_epoch=False,
  228. prog_bar=False,
  229. logger=True,
  230. sync_dist=True,
  231. )
  232. self.log(
  233. "train/generator/loss_mel",
  234. loss_mel,
  235. on_step=True,
  236. on_epoch=False,
  237. prog_bar=False,
  238. logger=True,
  239. sync_dist=True,
  240. )
  241. self.log(
  242. "train/generator/loss_fm",
  243. loss_fm,
  244. on_step=True,
  245. on_epoch=False,
  246. prog_bar=False,
  247. logger=True,
  248. sync_dist=True,
  249. )
  250. self.log(
  251. "train/generator/loss_adv",
  252. loss_adv,
  253. on_step=True,
  254. on_epoch=False,
  255. prog_bar=False,
  256. logger=True,
  257. sync_dist=True,
  258. )
  259. self.log(
  260. "train/generator/loss_vq",
  261. loss_vq,
  262. on_step=True,
  263. on_epoch=False,
  264. prog_bar=False,
  265. logger=True,
  266. sync_dist=True,
  267. )
  268. optim_g.zero_grad()
  269. self.manual_backward(loss_gen_all)
  270. self.clip_gradients(
  271. optim_g, gradient_clip_val=1.0, gradient_clip_algorithm="norm"
  272. )
  273. optim_g.step()
  274. # Manual LR Scheduler
  275. scheduler_g, scheduler_d = self.lr_schedulers()
  276. scheduler_g.step()
  277. scheduler_d.step()
  278. def validation_step(self, batch: Any, batch_idx: int):
  279. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  280. audios = audios.float()
  281. audios = audios[:, None, :]
  282. features = gt_mels = self.mel_transform(audios, sample_rate=self.sampling_rate)
  283. if self.downsample is not None:
  284. features = self.downsample(features)
  285. mel_lengths = audio_lengths // self.hop_length
  286. feature_lengths = (
  287. audio_lengths
  288. / self.hop_length
  289. / (self.downsample.total_strides if self.downsample is not None else 1)
  290. ).long()
  291. feature_masks = torch.unsqueeze(
  292. sequence_mask(feature_lengths, features.shape[2]), 1
  293. ).to(gt_mels.dtype)
  294. mel_masks = torch.unsqueeze(sequence_mask(mel_lengths, gt_mels.shape[2]), 1).to(
  295. gt_mels.dtype
  296. )
  297. # vq_features is 50 hz, need to convert to true mel size
  298. text_features = self.mel_encoder(features, feature_masks)
  299. text_features, _, _ = self.vq_encoder(text_features, feature_masks)
  300. text_features = F.interpolate(
  301. text_features, size=gt_mels.shape[2], mode="nearest"
  302. )
  303. # Sample mels
  304. if self.decoder is not None:
  305. speaker_features = (
  306. self.speaker_encoder(gt_mels, mel_masks)
  307. if self.speaker_encoder is not None
  308. else None
  309. )
  310. decoded_mels = self.decoder(text_features, mel_masks, g=speaker_features)
  311. else:
  312. decoded_mels = text_features
  313. fake_audios = self.generator(decoded_mels)
  314. fake_mels = self.mel_transform(fake_audios.squeeze(1))
  315. min_mel_length = min(
  316. decoded_mels.shape[-1], gt_mels.shape[-1], fake_mels.shape[-1]
  317. )
  318. decoded_mels = decoded_mels[:, :, :min_mel_length]
  319. gt_mels = gt_mels[:, :, :min_mel_length]
  320. fake_mels = fake_mels[:, :, :min_mel_length]
  321. mel_loss = F.l1_loss(gt_mels * mel_masks, fake_mels * mel_masks)
  322. self.log(
  323. "val/mel_loss",
  324. mel_loss,
  325. on_step=False,
  326. on_epoch=True,
  327. prog_bar=True,
  328. logger=True,
  329. sync_dist=True,
  330. )
  331. for idx, (
  332. mel,
  333. gen_mel,
  334. decode_mel,
  335. audio,
  336. gen_audio,
  337. audio_len,
  338. ) in enumerate(
  339. zip(
  340. gt_mels,
  341. fake_mels,
  342. decoded_mels,
  343. audios.detach().float(),
  344. fake_audios.detach().float(),
  345. audio_lengths,
  346. )
  347. ):
  348. mel_len = audio_len // self.hop_length
  349. image_mels = plot_mel(
  350. [
  351. gen_mel[:, :mel_len],
  352. decode_mel[:, :mel_len],
  353. mel[:, :mel_len],
  354. ],
  355. [
  356. "Generated",
  357. "Decoded",
  358. "Ground-Truth",
  359. ],
  360. )
  361. if isinstance(self.logger, WandbLogger):
  362. self.logger.experiment.log(
  363. {
  364. "reconstruction_mel": wandb.Image(image_mels, caption="mels"),
  365. "wavs": [
  366. wandb.Audio(
  367. audio[0, :audio_len],
  368. sample_rate=self.sampling_rate,
  369. caption="gt",
  370. ),
  371. wandb.Audio(
  372. gen_audio[0, :audio_len],
  373. sample_rate=self.sampling_rate,
  374. caption="prediction",
  375. ),
  376. ],
  377. },
  378. )
  379. if isinstance(self.logger, TensorBoardLogger):
  380. self.logger.experiment.add_figure(
  381. f"sample-{idx}/mels",
  382. image_mels,
  383. global_step=self.global_step,
  384. )
  385. self.logger.experiment.add_audio(
  386. f"sample-{idx}/wavs/gt",
  387. audio[0, :audio_len],
  388. self.global_step,
  389. sample_rate=self.sampling_rate,
  390. )
  391. self.logger.experiment.add_audio(
  392. f"sample-{idx}/wavs/prediction",
  393. gen_audio[0, :audio_len],
  394. self.global_step,
  395. sample_rate=self.sampling_rate,
  396. )
  397. plt.close(image_mels)