Cyclegan-for-music-generate

论文名称:Symbolic Music Genre Transfer with CycleGAN

作者:Gino Brunner, Yuyi Wang, Roger Wattenhofer and Sumu Zhao

Code:https://github.com/sumuzhao/CycleGAN-Music-Style-Transfer

前言

本文使用Cycle Gan实现了不同音乐类型的转换,在原有模型的基础上,引入了新的loss提升生成的音乐质量.

网络结构

image-20210615195420518

标识(嫌太麻烦可以先看2.1):

  1. 蓝线:表示从源域A目标域B再到源域A的转换
  2. 红线:表示从目标域B源域A再到目标域B的转换
  3. 黑线:指向损失函数
  4. G A → B , G B → A G_{A\rightarrow B},G_{B\rightarrow A} GAB,GBA:表示在两个域之间转换的生成器
  5. D A , D B D_A,D_B DA,DB:表示两个域的判别器
  6. D A , m , D B , m D_{A,m},D_{B,m} DA,m,DB,m表示两个额外的判别器,其迫使生成器学习更多的高级特征
  7. x A , x B x_A,x_B xA,xB:表示来自源域A目标域B中的真实样本数据,同时也是网络的输入
  8. x ^ B \hat{x}_B x^B:表示转换到目标域B的样本数据,记为 x ^ B = G A → B ( x A ) \hat x_B=G_{A\rightarrow B}(x_A) x^B=GAB(xA)
  9. x ~ B \tilde{x}_B x~B:表示转换回目标域B的样本数据,记为 x ~ B = G A → B ( x ^ A ) = G A → B ( G B → A ( x B ) ) \tilde{x}_B=G_{A\rightarrow B}(\hat{x}_A)=G_{A\rightarrow B}(G_{B\rightarrow A}(x_B)) x~B=GAB(x^A)=GAB(GBA(xB))
  10. x ~ A \tilde{x}_A x~A:表示转换回源域A的样本数据,记为 x ~ A = G B → A ( x ^ B ) = G B → A ( G A → B ( x A ) ) \tilde{x}_A=G_{B\rightarrow A}(\hat{x}_B)=G_{B\rightarrow A}(G_{A\rightarrow B}(x_A)) x~A=GBA(x^B)=GBA(GAB(xA))
  11. x ^ A \hat{x}_A x^A:表示转换到源域A的样本数据,记为 x ^ A = G B → A ( x B ) \hat{x}_A=G_{B\rightarrow A}(x_B) x^A=GBA(xB)
  12. M:是一个包含多个域的音乐集,例如 M = A ∪ B M=A\cup B M=AB,但也可能 M ⊃ A ∪ B M\supset A\cup B MAB
  13. x M x_M xM:表示来自M的样本数据

对于各种样本数据,带有 ^ \hat{} ^上标表示中间输出,带有 ~ \tilde{} ~上标表示最终输出

简化结构

让我们分以下几步来简化这个结构

  1. 忽略判别器,因为判别器就相当于一个损失函数
  2. 只提取出其中的 G A → B , G B → A G_{A\rightarrow B},G_{B\rightarrow A} GAB,GBA

接下来,让我们仅仅针对 x A x_A xA来看一下它的对抗网络之旅

  1. 首先 x A x_A xA会输入 G A → B G_{A\rightarrow B} GAB得到中间输出 x ^ B \hat{x}_B x^B
  2. x ^ B \hat{x}_B x^B会输入 G B → A G_{B\rightarrow A} GBA得到最终输出 x ~ A \tilde{x}_A x~A

至此,我们称这是一个循环,我们会对中间输出 x ^ B \hat{x}_B x^B x B x_B xB求损失

同理,对于 x B x_B xB,会进行一个反向的循环,即先输给 G B → A G_{B\rightarrow A} GBA再输入给 G A → B G_{A\rightarrow B} GAB,得到 x ^ A \hat{x}_A x^A x ~ B \tilde{x}_B x~B,同样会对 x ^ A \hat{x}_A x^A x A x_A xA求损失

此时我们得到了两个最终输出 x ~ A , x ~ B \tilde{x}_A,\tilde{x}_B x~A,x~B,分别和 x A , x B x_A,x_B xA,xB求损失( 见下循环一致损失)

生成器结构

image-20210616162851000

image-20210616163005547

判别器结构

image-20210616162940240

image-20210616162916705

分类器结构

image-20210616163035862

image-20210616163056246

损失函数

生成器损失

总损失如下
L G = l G A → B + l G B → A + λ L c L_G=l_{G_{A\rightarrow B}}+l_{G_{B\rightarrow A}}+\lambda L_c LG=lGAB+lGBA+λLc
其分为两个部分:对抗损失和循环一致损失

这里的 λ \lambda λ表示循环一致损失的权重,论文中是10

对抗损失

使用 L 2 l o s s L2\quad loss L2loss来作为生成器的损失
L G A → B = ∣ ∣ D B ( x ^ B ) − 1 ∣ ∣ 2 L G B → A = ∣ ∣ D A ( x ^ A ) − 1 ∣ ∣ 2 L_{G_{A\rightarrow B}}=||D_B(\hat{x}_B)-1||_2\\ L_{G_{B\rightarrow A}}=||D_A(\hat{x}_A)-1||_2 LGAB=DB(x^B)12LGBA=DA(x^A)12
对于生成器,我们希望其生成的数据都被判定为真,从而欺骗判别器,因此这里减去1,1即代表着标签

循环一致损失

在此前的工作中,为了加强前后一致性,进入了一个 L 1 n o r m L1\quad norm L1norm作为损失项,被称为循环一致损失( cycle consistency loss)
L c = ∣ ∣ x ~ A − x A ∣ ∣ 1 + ∣ ∣ x ~ B − x B ∣ ∣ 1 L_c=||\tilde{x}_A-x_A||_1+||\tilde{x}_B-x_B||_1 Lc=x~AxA1+x~BxB1
循环一致损失保证了输入经过两个生成器之后,即完成了一次循环,最终能被映射回自身

如果取消循环一致损失,输入与输出之间的关系将大大减弱

同时,循环一致损失也可以看做一个正则化项,它保证了生成器不忽略输入的数据,而是保留更多必要信息,以完成反向转换

判别器损失

L D , a l l = L D + γ ( L D A , m + L D B , m ) L_{D,all}=L_D+\gamma(L_{D_{A,m}}+L_{D_{B,m}}) LD,all=LD+γ(LDA,m+LDB,m)

GAN的训练是高度不平衡的,通常在早期判别器会过度强大,从而导致网络收敛到一个很差的局部最优

此外,对于风格迁移任务还存在着另一个困难:生成器需要学习源域和目标域的两种特征来欺骗判别器,然而生成器可以通过生成某种音乐类型独有的模式来欺骗判别器,这样即使判别器被欺骗了,生成器的生成也不一定是真实的。因此添加了两个额外的判别器来迫使生成器学习到更优的高级特征,并且使用了约束损失(我自己这么叫的)

其中 γ \gamma γ用来加权鉴别器的额外损失,论文中是1

为了保持训练的稳定性,同时添加了高斯噪声到判别器的输入(这应该是为了缓解判别器前期过于强大的情况)

标准判别器损失

L D A = 1 2 ( ∣ ∣ D A ( x A ) − 1 ∣ ∣ 2 + ∣ ∣ D A ( x ^ A ) ) ∣ ∣ 2 ) L D B = 1 2 ( ∣ ∣ D B ( x B ) − 1 ∣ ∣ 2 + ∣ ∣ D B ( x ^ B ) ) ∣ ∣ 2 ) L_{D_A}=\frac{1}{2}(||D_A(x_A)-1||_2+||D_A(\hat{x}_A))||_2)\\ L_{D_B}=\frac{1}{2}(||D_B(x_B)-1||_2+||D_B(\hat{x}_B))||_2) LDA=21(DA(xA)12+DA(x^A))2)LDB=21(DB(xB)12+DB(x^B))2)

约束损失

L D A , m = 1 2 ( ∣ ∣ D A , m ( x M ) − 1 ∣ ∣ 2 + ∣ ∣ D A , m ( x ^ A ) ∣ ∣ 2 ) L D B , m = 1 2 ( ∣ ∣ D B , m ( x M ) − 1 ∣ ∣ 2 + ∣ ∣ D B , m ( x ^ B ) ∣ ∣ 2 ) L_{D_{A,m}}=\frac{1}{2}(||D_{A,m}(x_M)-1||_2+||D_{A,m}(\hat{x}_A)||_2)\\ L_{D_{B,m}}=\frac{1}{2}(||D_{B,m}(x_M)-1||_2+||D_{B,m}(\hat{x}_B)||_2) LDA,m=21(DA,m(xM)12+DA,m(x^A)2)LDB,m=21(DB,m(xM)12+DB,m(x^B)2)

D B , m , D A , m D_{B,m},D_{A,m} DB,m,DA,m主要使用生成的假数据和多个域中的数据 x M x_M xM进行训练

这有助于使生成器保持在“音乐流形”上,并生成逼真的音乐。更重要的是,它让生成器保留了许多输入结构,从而确保在转换后仍然能够识别出原始内容。

简单来说,我认为这两个判别器起到了一个约束的作用,其目的是将生成的音乐约束限制在音乐域 M M M中,从而解决上述第二个问题

先将生成器生成约束在真实音乐的范围,再由其他判别器和损失函数增强其相应音乐风格转换的能力

数据集和处理

MIDI格式

与波形文件不同,MIDI文件不对音乐进行采样,而是将每一个音符记录为一个数字

虽然midi缺乏重现真实自然声音的能力,但是这是一种很好的将音乐离散化的方法

MIDI文件拥有note onnote off两种信号,note on消息指示一个音符开始被演奏,它还指定了该音符的速度(响度)。note off消息表示一个注释的结束。

采样策略

我们以每小节16个时间步对MIDI文件进行采样,因为绝大部分部分小节当中一个拍子的音符时值都不会低于十六分音符

我们最终的数据维度是 ( t , p ) (t,p) (t,p) t , p t,p tp分别表示采样时间步的大小和音高

同时将速度都设置为127,使他们的响度保持一致,这会使学习更简单,因为只有note on和note off两种状态

于是,数据维度也是表示为在每个时间步上包含一个 p p p维的 k − h o t k-hot khot向量, k k k为同时弹奏的音,此外,MIDI的音域大于钢琴的音域,我们只取了 p = 84 p=84 p=84,使用连续的4个小节作为而训练数据,因此数据维度大小为 ( 64 , 84 ) (64,84) (64,84)

音轨

一首乐曲通常有很多音轨,若是忽略了伴奏会丢失很多原有的信息,因此,做了一个简单的处理:将所有音轨合并为一个音轨。

这样可以保留大部分原有信息,然而所有的不同音轨通常由不同乐器演奏,这样一来,所有音轨都会变为一种乐器演奏,生成时便会显得十分凌乱

此外,还去除了鼓的音轨,因为使用其他乐器演奏他通常很奇怪

数据处理

首先,过滤掉第一拍不以0开始的MIDI文件

然后删除掉拍号不为4/4拍或者会在中途改变的曲目

最终得到12,341个爵士、16,545个古典和20,780个流行音乐采样,每个文件包含4个小节

为了避免不同流派音乐数据的不均衡,训练时会减少大数据集的样本数,与小数据集进行匹配,如当训练爵士和古典时,从古典音乐中随即抽取12,341个文件

在预处理阶段,将数据归一化

训练

GAN的训练总是很不稳定,生成器和判别器需要小心翼翼地平衡

引入了Instance NormLeakyReLU

使用Adam优化器, α = 0.0002 \alpha = 0.0002 α=0.0002 β 1 = 0.5 \beta_1 = 0.5 β1=0.5 β 2 = 0.999 \beta_2 = 0.999 β2=0.999 B a t c h s i z e = 16 Batchsize=16 Batchsize=16 e p o c h = 30 epoch=30 epoch=30

代码复现

https://github.com/Asthestarsfalll/Symbolic-Music-Genre-Transfer-with-CycleGAN-for-pytorch

然而在11g显存的显卡上Batch_size只能设置为1,而论文中为16,应该某些地方有问题

并且测试中总会出现输出为极小的情况,导致最终保存的MIDI文件为空,作者的代码似乎也有类似的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值