lit_module.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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. ):
  49. super().__init__()
  50. # Model parameters
  51. self.optimizer_builder = optimizer
  52. self.lr_scheduler_builder = lr_scheduler
  53. # Generator and discriminators
  54. self.downsample = downsample
  55. self.vq_encoder = vq_encoder
  56. self.mel_encoder = mel_encoder
  57. self.decoder = decoder
  58. self.generator = generator
  59. self.discriminator = discriminator
  60. self.mel_transform = mel_transform
  61. # Crop length for saving memory
  62. self.segment_size = segment_size
  63. self.hop_length = hop_length
  64. self.sampling_rate = sample_rate
  65. self.freeze_hifigan = freeze_hifigan
  66. # Disable automatic optimization
  67. self.automatic_optimization = False
  68. # Stage 1: Train the VQ only
  69. if self.freeze_hifigan:
  70. for p in self.discriminator.parameters():
  71. p.requires_grad = False
  72. for p in self.generator.parameters():
  73. p.requires_grad = False
  74. # Stage 2: Train the HifiGAN + Decoder + Generator
  75. if freeze_vq:
  76. for p in self.vq_encoder.parameters():
  77. p.requires_grad = False
  78. for p in self.mel_encoder.parameters():
  79. p.requires_grad = False
  80. for p in self.downsample.parameters():
  81. p.requires_grad = False
  82. def configure_optimizers(self):
  83. # Need two optimizers and two schedulers
  84. optimizer_generator = self.optimizer_builder(
  85. itertools.chain(
  86. self.downsample.parameters(),
  87. self.vq_encoder.parameters(),
  88. self.mel_encoder.parameters(),
  89. self.decoder.parameters(),
  90. self.generator.parameters(),
  91. )
  92. )
  93. optimizer_discriminator = self.optimizer_builder(
  94. self.discriminator.parameters()
  95. )
  96. lr_scheduler_generator = self.lr_scheduler_builder(optimizer_generator)
  97. lr_scheduler_discriminator = self.lr_scheduler_builder(optimizer_discriminator)
  98. return (
  99. {
  100. "optimizer": optimizer_generator,
  101. "lr_scheduler": {
  102. "scheduler": lr_scheduler_generator,
  103. "interval": "step",
  104. "name": "optimizer/generator",
  105. },
  106. },
  107. {
  108. "optimizer": optimizer_discriminator,
  109. "lr_scheduler": {
  110. "scheduler": lr_scheduler_discriminator,
  111. "interval": "step",
  112. "name": "optimizer/discriminator",
  113. },
  114. },
  115. )
  116. def training_step(self, batch, batch_idx):
  117. optim_g, optim_d = self.optimizers()
  118. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  119. audios = audios.float()
  120. audios = audios[:, None, :]
  121. with torch.no_grad():
  122. features = gt_mels = self.mel_transform(
  123. audios, sample_rate=self.sampling_rate
  124. )
  125. if self.downsample is not None:
  126. features = self.downsample(features)
  127. mel_lengths = audio_lengths // self.hop_length
  128. feature_lengths = (
  129. audio_lengths
  130. / self.hop_length
  131. / (self.downsample.total_strides if self.downsample is not None else 1)
  132. ).long()
  133. feature_masks = torch.unsqueeze(
  134. sequence_mask(feature_lengths, features.shape[2]), 1
  135. ).to(gt_mels.dtype)
  136. mel_masks = torch.unsqueeze(sequence_mask(mel_lengths, gt_mels.shape[2]), 1).to(
  137. gt_mels.dtype
  138. )
  139. # vq_features is 50 hz, need to convert to true mel size
  140. text_features = self.mel_encoder(features, feature_masks)
  141. text_features, _, loss_vq = self.vq_encoder(text_features, feature_masks)
  142. text_features = F.interpolate(
  143. text_features, size=gt_mels.shape[2], mode="nearest"
  144. )
  145. # Sample mels
  146. decoded_mels = self.decoder(text_features, mel_masks)
  147. fake_audios = self.generator(decoded_mels)
  148. y_hat_mels = self.mel_transform(fake_audios.squeeze(1))
  149. y, ids_slice = rand_slice_segments(audios, audio_lengths, self.segment_size)
  150. y_hat = slice_segments(fake_audios, ids_slice, self.segment_size)
  151. assert y.shape == y_hat.shape, f"{y.shape} != {y_hat.shape}"
  152. # Since we don't want to update the discriminator, we skip the backward pass
  153. if self.freeze_hifigan is False:
  154. # Discriminator
  155. y_d_hat_r, y_d_hat_g, _, _ = self.discriminator(y, y_hat.detach())
  156. with torch.autocast(device_type=audios.device.type, enabled=False):
  157. loss_disc_all, _, _ = discriminator_loss(y_d_hat_r, y_d_hat_g)
  158. self.log(
  159. "train/discriminator/loss",
  160. loss_disc_all,
  161. on_step=True,
  162. on_epoch=False,
  163. prog_bar=True,
  164. logger=True,
  165. sync_dist=True,
  166. )
  167. optim_d.zero_grad()
  168. self.manual_backward(loss_disc_all)
  169. self.clip_gradients(
  170. optim_d, gradient_clip_val=1.0, gradient_clip_algorithm="norm"
  171. )
  172. optim_d.step()
  173. y_d_hat_r, y_d_hat_g, fmap_r, fmap_g = self.discriminator(y, y_hat)
  174. with torch.autocast(device_type=audios.device.type, enabled=False):
  175. loss_decoded_mel = F.l1_loss(gt_mels * mel_masks, decoded_mels * mel_masks)
  176. loss_mel = F.l1_loss(gt_mels * mel_masks, y_hat_mels * mel_masks)
  177. loss_adv, _ = generator_loss(y_d_hat_g)
  178. loss_fm = feature_loss(fmap_r, fmap_g)
  179. if self.freeze_hifigan is True:
  180. loss_gen_all = loss_decoded_mel + loss_vq
  181. else:
  182. loss_gen_all = loss_mel * 45 + loss_vq * 45 + loss_fm + loss_adv
  183. self.log(
  184. "train/generator/loss",
  185. loss_gen_all,
  186. on_step=True,
  187. on_epoch=False,
  188. prog_bar=True,
  189. logger=True,
  190. sync_dist=True,
  191. )
  192. self.log(
  193. "train/generator/loss_decoded_mel",
  194. loss_decoded_mel,
  195. on_step=True,
  196. on_epoch=False,
  197. prog_bar=False,
  198. logger=True,
  199. sync_dist=True,
  200. )
  201. self.log(
  202. "train/generator/loss_mel",
  203. loss_mel,
  204. on_step=True,
  205. on_epoch=False,
  206. prog_bar=False,
  207. logger=True,
  208. sync_dist=True,
  209. )
  210. self.log(
  211. "train/generator/loss_fm",
  212. loss_fm,
  213. on_step=True,
  214. on_epoch=False,
  215. prog_bar=False,
  216. logger=True,
  217. sync_dist=True,
  218. )
  219. self.log(
  220. "train/generator/loss_adv",
  221. loss_adv,
  222. on_step=True,
  223. on_epoch=False,
  224. prog_bar=False,
  225. logger=True,
  226. sync_dist=True,
  227. )
  228. self.log(
  229. "train/generator/loss_vq",
  230. loss_vq,
  231. on_step=True,
  232. on_epoch=False,
  233. prog_bar=False,
  234. logger=True,
  235. sync_dist=True,
  236. )
  237. optim_g.zero_grad()
  238. self.manual_backward(loss_gen_all)
  239. self.clip_gradients(
  240. optim_g, gradient_clip_val=1.0, gradient_clip_algorithm="norm"
  241. )
  242. optim_g.step()
  243. # Manual LR Scheduler
  244. scheduler_g, scheduler_d = self.lr_schedulers()
  245. scheduler_g.step()
  246. scheduler_d.step()
  247. def validation_step(self, batch: Any, batch_idx: int):
  248. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  249. audios = audios.float()
  250. audios = audios[:, None, :]
  251. features = gt_mels = self.mel_transform(audios, sample_rate=self.sampling_rate)
  252. if self.downsample is not None:
  253. features = self.downsample(features)
  254. mel_lengths = audio_lengths // self.hop_length
  255. feature_lengths = (
  256. audio_lengths
  257. / self.hop_length
  258. / (self.downsample.total_strides if self.downsample is not None else 1)
  259. ).long()
  260. feature_masks = torch.unsqueeze(
  261. sequence_mask(feature_lengths, features.shape[2]), 1
  262. ).to(gt_mels.dtype)
  263. mel_masks = torch.unsqueeze(sequence_mask(mel_lengths, gt_mels.shape[2]), 1).to(
  264. gt_mels.dtype
  265. )
  266. # vq_features is 50 hz, need to convert to true mel size
  267. text_features = self.mel_encoder(features, feature_masks)
  268. text_features, _, _ = self.vq_encoder(text_features, feature_masks)
  269. text_features = F.interpolate(
  270. text_features, size=gt_mels.shape[2], mode="nearest"
  271. )
  272. # Sample mels
  273. decoded_mels = self.decoder(text_features, mel_masks)
  274. fake_audios = self.generator(decoded_mels)
  275. fake_mels = self.mel_transform(fake_audios.squeeze(1))
  276. min_mel_length = min(
  277. decoded_mels.shape[-1], gt_mels.shape[-1], fake_mels.shape[-1]
  278. )
  279. decoded_mels = decoded_mels[:, :, :min_mel_length]
  280. gt_mels = gt_mels[:, :, :min_mel_length]
  281. fake_mels = fake_mels[:, :, :min_mel_length]
  282. mel_loss = F.l1_loss(gt_mels * mel_masks, fake_mels * mel_masks)
  283. self.log(
  284. "val/mel_loss",
  285. mel_loss,
  286. on_step=False,
  287. on_epoch=True,
  288. prog_bar=True,
  289. logger=True,
  290. sync_dist=True,
  291. )
  292. for idx, (
  293. mel,
  294. gen_mel,
  295. decode_mel,
  296. audio,
  297. gen_audio,
  298. audio_len,
  299. ) in enumerate(
  300. zip(
  301. gt_mels,
  302. fake_mels,
  303. decoded_mels,
  304. audios.detach().float(),
  305. fake_audios.detach().float(),
  306. audio_lengths,
  307. )
  308. ):
  309. mel_len = audio_len // self.hop_length
  310. image_mels = plot_mel(
  311. [
  312. gen_mel[:, :mel_len],
  313. decode_mel[:, :mel_len],
  314. mel[:, :mel_len],
  315. ],
  316. [
  317. "Generated",
  318. "Decoded",
  319. "Ground-Truth",
  320. ],
  321. )
  322. if isinstance(self.logger, WandbLogger):
  323. self.logger.experiment.log(
  324. {
  325. "reconstruction_mel": wandb.Image(image_mels, caption="mels"),
  326. "wavs": [
  327. wandb.Audio(
  328. audio[0, :audio_len],
  329. sample_rate=self.sampling_rate,
  330. caption="gt",
  331. ),
  332. wandb.Audio(
  333. gen_audio[0, :audio_len],
  334. sample_rate=self.sampling_rate,
  335. caption="prediction",
  336. ),
  337. ],
  338. },
  339. )
  340. if isinstance(self.logger, TensorBoardLogger):
  341. self.logger.experiment.add_figure(
  342. f"sample-{idx}/mels",
  343. image_mels,
  344. global_step=self.global_step,
  345. )
  346. self.logger.experiment.add_audio(
  347. f"sample-{idx}/wavs/gt",
  348. audio[0, :audio_len],
  349. self.global_step,
  350. sample_rate=self.sampling_rate,
  351. )
  352. self.logger.experiment.add_audio(
  353. f"sample-{idx}/wavs/prediction",
  354. gen_audio[0, :audio_len],
  355. self.global_step,
  356. sample_rate=self.sampling_rate,
  357. )
  358. plt.close(image_mels)
  359. class VQNaive(L.LightningModule):
  360. def __init__(
  361. self,
  362. optimizer: Callable,
  363. lr_scheduler: Callable,
  364. downsample: ConvDownSampler,
  365. vq_encoder: VQEncoder,
  366. speaker_encoder: SpeakerEncoder,
  367. mel_encoder: TextEncoder,
  368. decoder: TextEncoder,
  369. mel_transform: nn.Module,
  370. hop_length: int = 640,
  371. sample_rate: int = 32000,
  372. vocoder: Generator = None,
  373. ):
  374. super().__init__()
  375. # Model parameters
  376. self.optimizer_builder = optimizer
  377. self.lr_scheduler_builder = lr_scheduler
  378. # Generator and discriminators
  379. self.downsample = downsample
  380. self.vq_encoder = vq_encoder
  381. self.speaker_encoder = speaker_encoder
  382. self.mel_encoder = mel_encoder
  383. self.decoder = decoder
  384. self.mel_transform = mel_transform
  385. # Crop length for saving memory
  386. self.hop_length = hop_length
  387. self.sampling_rate = sample_rate
  388. # Vocoder
  389. self.vocoder = vocoder
  390. for p in self.vocoder.parameters():
  391. p.requires_grad = False
  392. def configure_optimizers(self):
  393. optimizer = self.optimizer_builder(self.parameters())
  394. lr_scheduler = self.lr_scheduler_builder(optimizer)
  395. return {
  396. "optimizer": optimizer,
  397. "lr_scheduler": {
  398. "scheduler": lr_scheduler,
  399. "interval": "step",
  400. },
  401. }
  402. def vq_encode(self, audios, audio_lengths):
  403. with torch.no_grad():
  404. features = gt_mels = self.mel_transform(
  405. audios, sample_rate=self.sampling_rate
  406. )
  407. if self.downsample is not None:
  408. features = self.downsample(features)
  409. mel_lengths = audio_lengths // self.hop_length
  410. feature_lengths = (
  411. audio_lengths
  412. / self.hop_length
  413. / (self.downsample.total_strides if self.downsample is not None else 1)
  414. ).long()
  415. feature_masks = torch.unsqueeze(
  416. sequence_mask(feature_lengths, features.shape[2]), 1
  417. ).to(gt_mels.dtype)
  418. mel_masks = torch.unsqueeze(sequence_mask(mel_lengths, gt_mels.shape[2]), 1).to(
  419. gt_mels.dtype
  420. )
  421. # vq_features is 50 hz, need to convert to true mel size
  422. text_features = self.mel_encoder(features, feature_masks)
  423. text_features, indices, loss_vq = self.vq_encoder(text_features, feature_masks)
  424. return mel_masks, gt_mels, text_features, indices, loss_vq
  425. def vq_decode(self, text_features, speaker_features, gt_mels, mel_masks):
  426. text_features = F.interpolate(
  427. text_features, size=gt_mels.shape[2], mode="nearest"
  428. )
  429. decoded_mels = self.decoder(text_features, mel_masks, g=speaker_features)
  430. return decoded_mels
  431. def training_step(self, batch, batch_idx):
  432. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  433. audios = audios.float()
  434. audios = audios[:, None, :]
  435. mel_masks, gt_mels, text_features, indices, loss_vq = self.vq_encode(
  436. audios, audio_lengths
  437. )
  438. speaker_features = self.speaker_encoder(gt_mels, mel_masks)
  439. decoded_mels = self.vq_decode(
  440. text_features, speaker_features, gt_mels, mel_masks
  441. )
  442. loss_mel = F.l1_loss(gt_mels * mel_masks, decoded_mels * mel_masks)
  443. loss = loss_mel + loss_vq
  444. self.log(
  445. "train/generator/loss",
  446. loss,
  447. on_step=True,
  448. on_epoch=False,
  449. prog_bar=True,
  450. logger=True,
  451. sync_dist=True,
  452. )
  453. self.log(
  454. "train/loss_mel",
  455. loss_mel,
  456. on_step=True,
  457. on_epoch=False,
  458. prog_bar=False,
  459. logger=True,
  460. sync_dist=True,
  461. )
  462. self.log(
  463. "train/generator/loss_vq",
  464. loss_vq,
  465. on_step=True,
  466. on_epoch=False,
  467. prog_bar=False,
  468. logger=True,
  469. sync_dist=True,
  470. )
  471. return loss
  472. def validation_step(self, batch: Any, batch_idx: int):
  473. audios, audio_lengths = batch["audios"], batch["audio_lengths"]
  474. audios = audios.float()
  475. audios = audios[:, None, :]
  476. mel_masks, gt_mels, text_features, indices, loss_vq = self.vq_encode(
  477. audios, audio_lengths
  478. )
  479. speaker_features = self.speaker_encoder(gt_mels, mel_masks)
  480. decoded_mels = self.vq_decode(
  481. text_features, speaker_features, gt_mels, mel_masks
  482. )
  483. fake_audios = self.vocoder(decoded_mels)
  484. mel_loss = F.l1_loss(gt_mels * mel_masks, decoded_mels * mel_masks)
  485. self.log(
  486. "val/mel_loss",
  487. mel_loss,
  488. on_step=False,
  489. on_epoch=True,
  490. prog_bar=True,
  491. logger=True,
  492. sync_dist=True,
  493. )
  494. for idx, (
  495. mel,
  496. decoded_mel,
  497. audio,
  498. gen_audio,
  499. audio_len,
  500. ) in enumerate(
  501. zip(
  502. gt_mels,
  503. decoded_mels,
  504. audios.detach().float(),
  505. fake_audios.detach().float(),
  506. audio_lengths,
  507. )
  508. ):
  509. mel_len = audio_len // self.hop_length
  510. image_mels = plot_mel(
  511. [
  512. decoded_mel[:, :mel_len],
  513. mel[:, :mel_len],
  514. ],
  515. [
  516. "Generated",
  517. "Ground-Truth",
  518. ],
  519. )
  520. if isinstance(self.logger, WandbLogger):
  521. self.logger.experiment.log(
  522. {
  523. "reconstruction_mel": wandb.Image(image_mels, caption="mels"),
  524. "wavs": [
  525. wandb.Audio(
  526. audio[0, :audio_len],
  527. sample_rate=self.sampling_rate,
  528. caption="gt",
  529. ),
  530. wandb.Audio(
  531. gen_audio[0, :audio_len],
  532. sample_rate=self.sampling_rate,
  533. caption="prediction",
  534. ),
  535. ],
  536. },
  537. )
  538. if isinstance(self.logger, TensorBoardLogger):
  539. self.logger.experiment.add_figure(
  540. f"sample-{idx}/mels",
  541. image_mels,
  542. global_step=self.global_step,
  543. )
  544. self.logger.experiment.add_audio(
  545. f"sample-{idx}/wavs/gt",
  546. audio[0, :audio_len],
  547. self.global_step,
  548. sample_rate=self.sampling_rate,
  549. )
  550. self.logger.experiment.add_audio(
  551. f"sample-{idx}/wavs/prediction",
  552. gen_audio[0, :audio_len],
  553. self.global_step,
  554. sample_rate=self.sampling_rate,
  555. )
  556. plt.close(image_mels)